pax_global_header00006660000000000000000000000064150245674640014527gustar00rootroot0000000000000052 comment=766a2dd09f66693ad96891a65a4770f58fa5fd76 librecast/000077500000000000000000000000001502456746400130435ustar00rootroot00000000000000librecast/.gitignore000066400000000000000000000003511502456746400150320ustar00rootroot00000000000000*.o *.a *.so* *.swp cov-int/ *.tgz net-setup *.log autom4te.cache/ Makefile src/Makefile test/Makefile doc/Makefile libs/Makefile config.status configure~ src/config.h include/librecast/crypto.h include/librecast/types.h test/*.test librecast/CHANGELOG.md000066400000000000000000000467401502456746400146670ustar00rootroot00000000000000# Changelog All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [0.11.2] - 2025-06-18 ### Added - more man pages - `lc_share_acquire(3)` - `lc_share_release(3)` - reference counting for `lc_share_t` and `mdex_t` - netlink interface detection (Linux) - example programs ### Changed - README: various updates - INSTALL: update dependencies list ### Fixed - ignore EADDRINUSE when binding socket - sync: limit active receiver groups - sync: use fixed width integer types in `net_tree_t` - sync: `lc_syncfile(3)`: fix filename printing - sync: atomically update sync recv stats - make realclean: recurse into `examples/` - libmld: fix some data races - configure: include `` in `` - define `_GNU_SOURCE` before including `` - remove RaptorQ conditional defines from net.h, add to types.h - fix ECHRNG define condition - install man7 directory - various minor bug fixes - various test fixes and improvements ## [0.11.1] - 2025-05-18 ### Fixed - check return value of `clock_gettime()` (CID 523709) - fix Out-of-bounds access (CID 523707) ## [0.11.0] - 2025-05-18 ### Added - add restricted channel support - `lc_token_new()` - `lc_keypair_new()` - `lc_keyring_init()` / `lc_keyring_free()` - `lc_keyring_add()` / `lc_keyring_del()` - `lc_keyring_has()` - `lc_channel_token_set()` - `lc_channel_filter_set()` - `lc_socket_channel_by_address()` - `lc_ctx_coding_get()` - `lc_socket_coding_get()` - `lc_channel_coding_get()` - librecast(7) man page ### Changed - handle ENOBUFS when sending - return information bytes for send + recv functions - update libmld for RFC 9777 changes ### Fixed - fix support for symmetric encryption with OTI - support socketpair with `lc_socket_multi_recv()` - ensure channel matches socket in recv calls - free symbols after decoding RaptorQ object - interupt recv calls with signal (EINTR) - `lc_channel_recv*`: require channel is bound - fixes to RaptorQ with OTI - fix restricted channel on socketpair with FEC - respect preset overhead in `lc_channel_send(3)` - fix sending of (NULL, 0) payloads with RaptorQ - libmld: ensure tests do not require liblibrecast - ensure build works without liblcrq - fix leak in socket recv code ## [0.10.0] - 2025-03-24 ### Added - support encodings on multi-channel sockets - enable automatic sending of K' + overhead packets with send calls. - API calls to preset RaptorQ overhead - lc_ctx_rq_overhead() - lc_channel_rq_overhead() - lc_socket_multi_recv() - lc_socket_multi_recvmsg() - RaptorQ test group (test/rq) ### Changed - update BLAKE3 to 1.7.0 - lc_channel_sendmsg() - support NULL msg parameter with RaptorQ for sending additional symbols, matching behaviour of lc_channel_send() - socket encoding combines all channel encoding bits - lc_channel_recv\*(3): MSG_DROP flag: silently drop packets received for wrong channel instead of returning an error - lc_channel_recv: multi-channel socket behaviour When calling lc_channel_recv(3) with multiple channels bound to a socket, return an error code when a packet for a different channel is received. - test 0042 - require networking ### Fixed - test.c - avoid logging deadlock ### Removed - Remove "OSI approved" logo from README By jumping on the AI/LLM bandwagon with the ill-conceived release of the OSAID, the OSI has lost its way. By not requiring the training data (which forms part of the source of an "AI" program) to be provided under an OSD-compatible license, the OSI has caved in to pressure from industry to water down the definition of Open Source and split the Open Source community. They had one job. ## [0.9.1] - 2024-11-01 ### Changed - updated BLAKE3 to 1.5.4 ### Fixed - fix build on armle - sundry minor bugfixes ## [0.9.0] - 2024-10-29 The release adds the new Router API, the socket OIL filter, and a whole bunch of other new API calls, fixes and improvements. This work was funded by NLnet through NGI Assure. NGI Assure is made possible with financial support from the European Commission's Next Generation Internet programme, under the aegis of DG Communications Networks, Content and Technology. This project has received funding from the European Union’s Horizon 2020 research and innovation programme under grant agreement No 957073. Also, we'd like to take this opportunity to thank Robert Martinez (mray) for our shiny new Librecast Logo! ### Added - Router API - lc_router_new() - lc_router_free() - lc_router_socket_add() - lc_router_socket_del() - lc_router_net() - create connected routers - lc_router_start() - lc_router_stop() - lc_router_socket_get() - lc_router_socket_set() - lc_router_port_set() - lc_router_port_unset() - lc_router_port_down() - lc_router_port_up() - lc_router_port_connect() - lc_router_port_disconnect() - lc_router_channel_bind() - lc_router_channel_unbind() - lc_router_lock() - lc_router_trylock() - lc_router_unlock() - lc_router_lockpair() - lc_router_onready() - router callback - lc_router_acquire() - router readlock - lc_router_release() - Router Topologies: - LC_TOPO_NONE - do not connect anything - LC_TOPO_CHAIN - routers are daisy-chained - LC_TOPO_RING - ring topology - LC_TOPO_TREE - loop-free spanning tree - LC_TOPO_STAR - root router is connected to all others - LC_TOPO_MESH - full mesh (all routers directly connected) - LC_TOPO_RANDOM - surprise! - LC_TOPO_BUTTERFLY - a fixed topology of 6 routers, commonly used in network coding examples - LC_TOPO_HONEYCOMB - creates a network of 3-port routers with a ring of 3 routers redundantly connected to n hexagon rings. - router speedtest - lc_channel_recvmsg() - track socket bytes sent - lc_socket_by_fd() - find socket by file descriptor - Add RaptorQ encoding support to lc_channel_sendmsg() - channel read locking - lc_channel_acquire() - lc_channel_release() - socket read locking - lc_socket_acquire() - lc_socket_release() - context read locking - lc_ctx_acquire() - lc_ctx_release() - lc_socket_recvmmsg() - receive multiple messages on a Librecast socket - make test/tsan (testing with -fsanitize=thread) - Context queue and worker threads - lc_ctx_queue_init() - lc_ctx_qpool_resize() - lc_ctx_queue_free() - lc_ctx_q() - lc_channel_socket_by_hash() - lc_channel_copy() - perform full copy of channel - Add lc_socketpair() - create a pair of connected sockets. - Socket OIL filter - Add socket OIL functions to API - lc_socket_oil_add() - lc_socket_oil_del() - Tracking of sending stats in lc_share() - various additional configure checks ### Changed - New Librecast Logo contributed by Robert Martinez (mray). - channel NACK logging: access structures atomically - defer socket close until lc_socket_release() - make memcheck: ignore "still reachable" - update BLAKE3 -> 1.5.1 - store full channel hash ### Fixed - support lcrq 0.0.1: conditionally compile OTI - Fix compiling without lcrq - make testloop: clean logs between test runs - thread safety improvements, fixing various data races - lc_socket_send() do not return error for 0 bytes - ensure ENOKEY is defined on non-Linux - fix leaks in tests 0047, 0064 - ensure socket thread is cancelled when socket is closed - various other minor bugfixes ### Removed - configure: remove GNU malloc macros - remove unused function lc_hashgroup() - removed unused uri field from lc_channel_t ## [0.8.0] - 2023-11-07 This release adds recursive directory tree syncing, along with additional debugging output and other bugfixes. ### Added - recursive directory syncing - mdex_sharepath() - return the network sharepath - mdexing and syncing of symlinks - make test/zzz - slow tests, not run as part of main test suite - context debugging functions - lc_ctx_debug() - set debug flags - lc_ctx_stream() - set debug message output stream - debug settings for printing files during mdexing - If mdex->debug has the MDEX_DEBUG_FILE flag set, then file names will be printed to mdex->stream during indexing - keep track of number of entries (files, directories) indexed ## Changed - lc_syncfilelocal: set file metadata ### Fixed - correctly handle mdexing and syncing of zero length files - doc: mdex_add(3) - correction - fix function declarations with no prototype (void) - lc_share: ensure errno is set on error - mld_start: set errno if LISTEN thread fails ## [0.7.0] - 2023-08-22 This release adds the file syncing, sharing, mdex, mtree and smolq APIs, along with various other new API calls and improvements. ### Added - sync API: file and data syncing API - smolq: small queue API - mdex: channel Indexing API - mdex_*() - mtree: merkle tree hashing API - lc_ctx_ifx() - set default interface for sockets and channels created with context - lc_ctx_ratelimit() - set ratelimit on context - lc_channel_ratelimit(): channel ratelimiting (sending) - lc_share() / lc_unshare() - multicast file sharing API - lc_channel_oti_peek() - LC_CODE_FEC_OTI - send/recv RaptorQ FEC Object Transmission Information headers - lc_channel_rq() - lc_hashtoaddr() - create IPv6 multicast addr from supplied hash and flags - context encoding functions - lc_ctx_coding_set() - lc_ctx_getkey() - lc_ctx_setkey() - lc_ctx_set_sym_key() - lc_ctx_set_pub_key() - man pages for various API calls - check for network before running network tests - packet timeout in lc_channel_recv_lcrq - MSG_DROP flag for testing ### Changed - default to configure --with-mld - use more portable __attribute__ syntax - improved test runner + logging - improved BPF filter for MLD packets - randomize RaptorQ repair symbols - send additional RaptorQ repair symbols (2x overhead) ### Fixed - lc_ctx_keygetorset, lc_channel_keygetorset - set errno on error - preserve errno in our various free functions - ifdef guard rq_free - lc_channel_recv() - calculate RaptorQ ESI correctly - various Makefile fixes - various configure fixes - various test fixes - libmld: limit BPF filter to icmp6 and ensure mrecs is a reasonable number - removed ineffective channel mlocks when setting encryption keys. These need to be done by the calling program or implemented in a separate API call. - test 0000-0044 - fix race condition - improved error handling in libmld - fix race in lc_channel_send_coded() - fixes to lc_channel_recv() RaptorQ decoding - fix sodium_bin2hex definition when libsodium not enabled - mld_state_grp_check(): set ENODEV - lc_socket_recv(), lc_socket_recvmsg() - set errno to EBADMSG on decoding failure - libmld: only set SO_REUSEPORT if defined - libmld: new BPF filter for MLD packets - filter some unwanted packets - libmld: mld_query_msg(): free cmsgbuf on error - replace RaptorQ repair symbols with original when received - fix buffer overrun when decoding - fix race in lc_channel_send_coded() - libmld: fix race in mld_start() - libmld: avoid bind() of mld->sock to avoid setsockopt failures - libmld: mld_start(): wait for netlink thread to be ready - libmld: error checking in mld_listen (BSD version) - define byteorder macros for macOS/Darwin ## Removed - lc_ctx_get_id() - lc_socket_get_id() - lc_channel_get_id() ## [0.6.1] - 2023-05-14 ### Fixed - fix library SONAME (0.5, not 0.5.1) ## [0.6.0] - 2023-05-07 ### Added - NACK/replay API calls - lc_channel_check_seqno() - lc_channel_detect_gaps() - lc_channel_nack_add_log() - lc_channel_nack_handler() - lc_channel_nack_handler_thr() - MLD API (merged in libmld) - FreeBSD, NetBSD and OpenBSD support for tap creation ## Changed - BLAKE3 upgraded to v1.3.3 ## Fixed - fix cross-building on incompatible architectures by directly linking ABI version - fix hash_generic_key() for BLAKE3 - various test fixes, including fixes for NetBSD and FreeBSD ## [0.5.1] - 2022-07-16 ### Fixed - CID 274982 Unchecked return value from library - check return from setsockopt() - CID 274984 Unchecked return value from library - check return from setsockopt() - CID 274983 Resource leak - free() on error path - fix fatal build bug ("missing" config.h) - blake3: disable NEON on arm64 - install: fix library symlink creation - minor test fixes ## [0.5.0] - 2022-07-14 ### Added - RaptorQ (RFC 6330) Forwards Error Correction - symmetric key message encryption - channel key management/encoding functions - lc_channel_setkey() - lc_channel_getkey() - lc_channel_set_sym_key() - lc_channel_set_pub_key() - lc_channel_coding_set - lc_channel_init_grp() - convenience function for calling lc_channel_init() - make net-setup, net-teardown, testshell targets for testing - configure + autotools build system - man lc_channel_coding_set(3) - define macro for crypto_secretbox_keygen() for libsodium < 1.0.12 ### Changed - Makefile changes, cleanup - various documentation updates ### Fixed - Gave Up Github (https://sfconservancy.org/GiveUpGitHub/). Hello Codeberg! - removed hardcoded bash path (was breaking tests on NixOS) - respect LDFLAGS and CPPFLAGS for hardening flags (#35) - test runner for {Free,Net}BSD - create required symlink - various build & test fixes on different systems ## [0.4.5] - 2022-04-04 ### Added - lc_tuntap_create() - create TUN/TAP sockets - lc_channel_random() - create random channel - tracking group joins per socket when IPV6_MULTICAST_ALL not defined This means ALL packets for ALL multicast groups joined by ANY PROCESS owned by ANY USER will be received by a socket by default. That's ... surprising. And not the behaviour we want. Librecast needs to track group joins per socket and drop any packets that aren't expected on that socket. - added Repology badge to README ### Changed - don't force clean before tests - use newer SIOCBRDELIF in bridge code - explicitly include to ensure SIOCBRDELIF defined ### Fixed - use non-default channel port if specified on recv - check for invalid opcodes before calling message handler - copy ancillary pkt info to ensure memory is aligned - fix test 20 on big endian - zero memory for device name array in test 32 - add missing header ## [0.4.4] - 2021-06-05 ### Added - lc_bridge_add() / lc_bridge_del() - lc_tap_create() - lc_link_set() - bring up / tear down network interfaces - lc_bridge_addif() / lc_bridge_delif() - fallback interface code for unsupported platforms - lc_channel_send() / lc_socket_recv() - raw channel/socket send/recv functions - lc_channel_sendmsg() / lc_socket_recvmsg() - lc_socket_bind() - join on all multicast-capable interfaces, or bound socket ifx - lc_socket_send() - send to all channels bound to socket - lc_socket_sendmsg() - lc_socket_ttl() - set socket TTL ### Changed - License changed to GPL-2.0 or GPL-3.0 (dual licenced) - Update README - irc channel moved to Libera.chat - Default hashing function changed to BLAKE2B from libsodium - libs/Makefile: Fix targets when building without blake3 - split bridge/interface code by O/S - remove -std=gnu99 from NetBSD build - required for NetBSD 7, no longer reqd for 9. ### Fixed - lc_msg_recv(): add cancellation point before recvmsg() - hangs on NetBSD without this. - lc_channel_bind(): set SO_REUSEPORT if defined - required on NetBSD to prevent "address already in use" errors. ## [0.4.3] - 2021-03-09 ### Fixed - Use IPV6_JOIN_GROUP / IPV6_LEAVE_GROUP in preference to obsolete IPV6_ADD_MEMBERSHIP / IPV6_DROP_MEMBERSHIP - Fix tempfile creation for tests on NetBSD. - Sort uses of "wildcard" in Makefile to make ordering of files predictible and avoid potential reproducibility issues. - Makefile fixes for NetBSD - replace call to ldconfig ## [0.4.2] - 2021-03-06 ### Added `` - hash_generic() - hash_generic_key() - hash_init() - hash_update() - hash_final() - hash_hex_debug() - hash_bin2hex() ### Changed - Changed default hashing function to BLAKE3. This is faster and and has similar security properties to BLAKE2B from libsodium. Build with `make USE_LIBSODIUM=1` to use BLAKE2B instead. ### Fixed - Support DESTDIR when installing docs. - Pass LIBDIR to ldconfig in the install target. - Building without libsodium. - Ensure a clean build before running single tests. - Work around bugs in gcc and glibc to fix test malloc ## [0.4.1] - 2021-03-04 ### Added - Instructions for Ubuntu to install prerequisite libsodium-dev (Esther Payne) ### Fixed - Remove references to obsolete libraries in test Makefile (Esther Payne) ## [0.4.0] - 2021-03-04 ### Added - CHANGELOG.md (this file) - test/falloc.c - failing malloc checker so we can force memory allocation failures in testing. - libsodium dependency (required for hashing) - valgrind.h added to `test/` so we can skip tests that don't play nicely with valgrind. ### Changed - The base multicast networking API has been reviewed, extensively refactored and simplified. - Functions were reordered more logically, grouping functions that call each other close together to improve efficiency. - Network interface indexes are now unsigned values everywhere. - Changes to the Channels API. lc_channel_init() now takes sockaddr_in6 so address and port can be directly specified and to save much converting back and forth between string and binary addresses. All calls to getaddrinfo() and use of struct addrinfo have been removed - there's really no need for this in multicast code. - Sockets and Channels are now inserted at the head of their lists. This is quicker, simplifies the code, and makes finding the most recently added faster. - SHA1 hash replaced with BLAKE2B from libsodium. - Renumbered error codes as negative. - lc_msg_logger() - optional message logging implemented as a function pointer ### Removed - The experimental database API has been removed completely for now, as it was intertwined with the network code. The core multicast code should not be require any database functionality or dependencies. This will be rewritten in the next milestone. - All logging has been removed. This is a library - we return error codes in serene silence and let the programmer decide what to do with them. - Removed some pointless argument checking in various API calls. A careless programmer won't be checking the return codes anyway. In some cases these have been replaced with assert()s to catch accidental API misuse. - OpenSSL dependency - libbridge dependency - Linux-specific headers - Removed obsolete tests. ### Fixed - docs (man pages) are now installed with `make install` ## [0.3.0] - 2020-09-05 ### Added - The code now compiles using either gcc or clang. There is a "make clang" target in the Makefile. - Added test runner and a set of test modules to the project to exercise all the main functions, including common error conditions. This will continue to be added to as I have adopted test driven development for the project. `make test` runs all the tests. `make check` runs all the tests using valgrind to do leak checking and dynamic analysis. `make 0000-0004.test` runs a single test. `make 0000-0004.check` runs a single test with valgrind `make 0000-0004.debug` runs a single test with the gdb debugger `make sparse` compiles the project using cgcc (the sparse static analyser) `make clang` builds the project using clang `make coverity` builds the project using the coverity static analyser, creating a librecast.tgz ready to upload to Coverity Scan for analysis. ### Changed - Split the library into three separate parts and removed some redundant code. - There are now separate headers and shared libraries for IPv6 Multicast messaging (net), local database commands and querying (lsdb) and remote (multicast) database commands (lcdb) librecast/CODE_OF_CONDUCT.md000066400000000000000000000064251502456746400156510ustar00rootroot00000000000000# Contributor Covenant Code of Conduct ## Our Pledge In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, religion, or sexual identity and orientation. ## Our Standards Examples of behavior that contributes to creating a positive environment include: * Using welcoming and inclusive language * Being respectful of differing viewpoints and experiences * Gracefully accepting constructive criticism * Focusing on what is best for the community * Showing empathy towards other community members Examples of unacceptable behavior by participants include: * The use of sexualized language or imagery and unwelcome sexual attention or advances * Trolling, insulting/derogatory comments, and personal or political attacks * Public or private harassment * Publishing others' private information, such as a physical or electronic address, without explicit permission * Other conduct which could reasonably be considered inappropriate in a professional setting ## Our Responsibilities Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. ## Scope This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. ## Enforcement Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at coc@librecast.net. All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. ## Attribution This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html [homepage]: https://www.contributor-covenant.org For answers to common questions about this code of conduct, see https://www.contributor-covenant.org/faq librecast/CONTRIBUTING.md000066400000000000000000000024561502456746400153030ustar00rootroot00000000000000# CONTRIBUTING Contributions are very welcome, both large and small. Correct patches (see Patch Requirements) will generally be accepted. This is a small project, so I don't want to get bogged down in too much formality, but in general I'm striving to follow Pieter Hintjens' Collective Code Construction Contract (C4) as used by the ZeroMQ project: https://rfc.zeromq.org/spec:42/C4/ ## Patch Requirements Maintainers and Contributors MUST have a Platform account and SHOULD use their real names or a well-known alias. A patch SHOULD be a minimal and accurate answer to exactly one identified and agreed problem. A patch MUST adhere to the code style guidelines of the project (see below) A patch SHALL NOT include non-trivial code from other projects unless the Contributor is the original author of that code. A patch MUST compile cleanly and pass project self-tests on at least the principal target platform. A patch commit message SHOULD consist of a single short (less than 50 character) line summarizing the change, optionally followed by a blank line and then a more thorough description. A "Correct Patch" is one that satisfies the above requirements. ## Coding Style This project uses the Linux kernel coding style: See https://www.kernel.org/doc/html/latest/process/coding-style.html librecast/COPYING000066400000000000000000000000661502456746400141000ustar00rootroot00000000000000SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only librecast/INSTALL.md000066400000000000000000000040001502456746400144650ustar00rootroot00000000000000# INSTALL ## Dependencies - libsodium (optional, but required for encryption) - liblcrq (optional, required for RaptorQ encoding) ## Installing from source The code compiles using either gcc or clang. There is a `make clang` target to force compilation with clang. The default is whatever your default CC is set to. NB: GNU Make is required. On \*BSD install and use gmake. The bash shell is also required for `make test`. Download the source: `git clone https://codeberg.org/librecast/librecast.git` then, do the usual: ``` cd librecast ./configure make make install # requires superuser (root/sudo) ``` NB: On Linux you may want to run `ldconfig` (as root) after installing to rebuild your library cache. You can set optimization flags for your platform by passing them to configure. eg.: ``` ./configure CFLAGS="-g -O3 -Wall -Wextra -pedantic -march=native -mpopcnt" ``` To install to a different location: `DESTDIR=/tmp make install` ## Uninstall `make uninstall` # requires superuser (root/sudo) ## Configure Options Librecast ships with BLAKE3 included. By default BLAKE3 is used as the hash function. This allows Librecast to build with no external dependencies. Provided you have libsodium installed you can use BLAKE2B from sodium instead. To disable blake3, configure with `--without-blake3`. If both BLAKE3 and BLAKE2B are enabled, BLAKE3 is used in preference. Libsodium is also used for encryption, if available. To explicitly *disable* libsodium (and all encryption capabilities), configure with `--without-sodium`. LibLCRQ for FEC will be enabled automatically, if found. To build without it, use `--without-lcrq`. NB: if you build with both of `--without-blake3 --without-sodium` librecast will not be able to create hashed channels, or do any other hashing. The tests will not run in this configuration. libMLD is built into liblibrecast by default. If you do *not* want to include the MLD API, disable by configuring with --without-mld. ### Install libsodium on Ubuntu `sudo apt install libsodium-dev` librecast/LICENSE.GPL-2.0-only000066400000000000000000000444511502456746400157550ustar00rootroot00000000000000Valid-License-Identifier: GPL-2.0 Valid-License-Identifier: GPL-2.0-only Valid-License-Identifier: GPL-2.0+ Valid-License-Identifier: GPL-2.0-or-later SPDX-URL: https://spdx.org/licenses/GPL-2.0.html Usage-Guide: To use this license in source code, put one of the following SPDX tag/value pairs into a comment according to the placement guidelines in the licensing rules documentation. For 'GNU General Public License (GPL) version 2 only' use: SPDX-License-Identifier: GPL-2.0 or SPDX-License-Identifier: GPL-2.0-only For 'GNU General Public License (GPL) version 2 or any later version' use: SPDX-License-Identifier: GPL-2.0+ or SPDX-License-Identifier: GPL-2.0-or-later License-Text: GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. librecast/LICENSE.GPL-3.0-only000066400000000000000000001045131502456746400157520ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 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 . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Copyright (C) This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . librecast/Makefile.in000066400000000000000000000060311502456746400151100ustar00rootroot00000000000000# SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only # Copyright (c) 2017-2025 Brett Sheffield PREFIX ?= @prefix@ export PREFIX PACKAGE_NAME := @PACKAGE_NAME@ PACKAGE_VERSION := @PACKAGE_VERSION@ LIBNAME := librecast LIBDIR := $(PREFIX)/lib LIBFILE := lib${LIBNAME}.so INCLUDEDIR := $(PREFIX)/include COVERITY_DIR := cov-int COVERITY_TGZ := $(PACKAGE_NAME)-coverity-$(PACKAGE_VERSION).tgz COVERITY_PATH=$(PATH):../../coverity/bin/ OSNAME := $(shell uname -s) export OSNAME export SOURCEDIR=$(shell pwd) ifeq ($(origin CC),default) CC = @CC@ endif export CC CFLAGS ?= @CFLAGS@ ifdef DEBUG CFLAGS += -Og -g -Wall -Wextra -pedantic endif export CFLAGS CPPFLAGS += @CPPFLAGS@ export CPPFLAGS LDFLAGS ?= @LDFLAGS@ export LDFLAGS all: src install: all doc $(MAKE) -C src $@ uninstall: $(MAKE) -C src $@ .PHONY: clean realclean src test testloop sparse doc libs netcheck net-teardown newtest testshell update examples update: $(MAKE) -C libs $@ libs: $(MAKE) -C $@ src: libs $(MAKE) -C $@ doc: $(MAKE) -C doc $@ examples: $(MAKE) -C $@ fixme: grep -n FIXME src/*.{c,h} test/*.{c,h} todo: grep -n TODO src/*.{c,h} test/*.{c,h} clean: $(MAKE) -C src $@ $(MAKE) -C test $@ $(MAKE) -C libs $@ $(MAKE) -C examples $@ realclean: clean $(MAKE) -C src $@ $(MAKE) -C test $@ $(MAKE) -C libs $@ $(MAKE) -C examples $@ $(RM) -r ./$(COVERITY_DIR) $(RM) $(COVERITY_TGZ) $(RM) Makefile $(RM) config.{log,status} $(RM) include/librecast/crypto.h $(RM) include/librecast/types.h sparse: clean CC=cgcc $(MAKE) src clang: clean CC=clang $(MAKE) src clangtest: clean CC=clang $(MAKE) test gcc: clean all netcheck: $(MAKE) -C test $@ test memcheck: src netcheck $(MAKE) -C libs $@ $(MAKE) -C test $@/all newtest: $(MAKE) -C test $@ LOOPBANNER ?= echo testloop: num_ok=0; \ while $(MAKE) $(subst testloop,test,$@); do \ num_ok=$$(( $$num_ok + 1 )); \ make -C test logclean; \ echo; \ echo; \ $(LOOPBANNER) "OK $$num_ok"; \ echo; \ sleep 1; \ done; \ $(LOOPBANNER) "OK $$num_ok" testloop/%: num_ok=0; \ while $(MAKE) $(subst testloop,test,$@); do \ num_ok=$$(( $$num_ok + 1 )); \ make -C test logclean; \ echo; \ echo; \ $(LOOPBANNER) "OK $$num_ok"; \ echo; \ done; \ $(LOOPBANNER) "OK $$num_ok" test/mld memcheck/mld: .FORCE all $(MAKE) -C libs $@ test/% memcheck/%: .FORCE src $(MAKE) -C test $@ .FORCE: # always recompile coverity: clean PATH=$(COVERITY_PATH) cov-build --dir cov-int $(MAKE) src tar czvf $(COVERITY_TGZ) $(COVERITY_DIR) net-setup: ip link add veth0 type veth peer name veth1 ip netns add vnet0 ip netns add vnet1 ip link set veth0 netns vnet0 ip link set veth1 netns vnet1 ip -n vnet0 link set veth0 up ip -n vnet1 link set veth1 up ip netns show touch net-setup net-teardown: ip -n vnet0 link set veth0 down ip -n vnet1 link set veth1 down ip -n vnet1 link set veth1 netns vnet0 ip -n vnet0 link del veth0 type veth peer name veth1 ip netns del vnet0 ip netns del vnet1 ip netns show rm -f net-setup testshell: @echo "sudo ip netns exec vnet0 sudo -u `id -un` /bin/bash" librecast/README.md000066400000000000000000000250221502456746400143230ustar00rootroot00000000000000# Librecast - Distributed Applications with IPv6 Multicast ![Librecast Logo](https://www.librecast.net/media/librecast.hex.svg) Coverity Scan Build Status Packaging status # README Librecast is a C multicast library which aims to make working with multicast easier. Librecast extends IPv6 multicast to provide a multicast communication layer with support for encodings, encryption, file syncing, router topologies and overlay multicast. ## Contents - [Background](#background) - [License](#license) - [Obtaining Librecast](#obtain) - [Installing Librecast](#install) - [Getting Started - Writing Librecast Programs](#getting-started) - [Bugs (also Questions and Feature Requests)](#bugs) - [Contact Us](#contact) - [Email](#contact-email) - [Fediverse (Mastodon)](#contact-fediverse) - [IRC](#contact-irc) - [Matrix](#contact-matrix) - [Code of Conduct](#coc) - [Contributing](#contributing) ## Background The [Librecast Project](https://librecast.net/) aims to enable universal group communication, and to provide the libraries and tools we need for that. Universal group communication is a requirement for human rights to flourish. Problems, such as climate change are global and affect the rights of all humans. Our ability to communicate, regardless of frontiers, is essential to our need to be informed, to organize, to promote and enjoy our rights, and to hold accountable those that would violate our rights. All organizations and power structures must be held accountable for human rights to have any meaning. To monitor and hold accountable global power structures such as corporations, governments and NGOs, we require global communication that is not subject to interference, interception or control by those powers. Our Internet is a requirement, not an option, for our global civilization, but that Internet is not fit for purpose. We need a Next Generation Internet (NGI) built around group communication and the tools to use it effectively. The Internet we have today is built for one-to-one communication (unicast), but our communication needs are many-to-many (multicast). Group communication built on top of unicast is inefficient and cumbersome, and often relies on centralized 3rd party servers controlled by large corporations. Together, we can change that and build a rights-respecting Next Generation Internet for all humans. ## License This work is dual-licensed under GPL 2.0 and GPL 3.0. `SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only` ## Obtaining Librecast Thanks to `vagrantc`, many of Librecast's libraries and tools are packaged for Debian, GUIX and Debian derivatives such as Ubuntu. Librecast is also available in [NixOS](https://search.nixos.org/packages?channel=24.11&from=0&size=50&sort=relevance&type=packages&query=librecast) thanks to the team at Summer of Nix. You can obtain the source code from Codeberg and SourceHut: ### liblibrecast - [Codeberg](https://codeberg.org/librecast/) - [SourceHut](https://sr.ht/~librecast/librecast/sources) ## Installing Librecast See [INSTALL.md](INSTALL.md). ## Getting Started - Programming with Librecast Let's look at two simple Librecast programs in C for sending and receiving data over IPv6 multicast: ### multicast sending program ``` /* Librecast sender example */ #include int main(void) { char data[] = "I have a dream"; ssize_t bytes; int rc = EXIT_FAILURE; /* pessimistic, aren't we? */ /* we start with a Librecast Context (lc_ctx_t) */ lc_ctx_t *lctx = lc_ctx_new(); if (!lctx) return rc; /* create a Librecast Socket (IPv6) */ lc_socket_t *sock = lc_socket_new(lctx); if (!sock) goto free_ctx; /* create a Librecast Channel */ lc_channel_t *chan = lc_channel_new(lctx, "my very first Librecast channel"); /* bind the Channel to the Socket */ lc_channel_bind(sock, chan); /* enable loopback, so we receive our own packets on the same host */ lc_socket_loop(sock, 1); /* (optional) enable RaptorQ encoding (RFC6330) */ lc_channel_coding_set(chan, LC_CODE_FEC_RQ | LC_CODE_FEC_OTI); lc_channel_rq_overhead(chan, RQ_OVERHEAD + 5); /* (optional) rate-limit sending */ lc_channel_ratelimit(chan, 104857600 /* 100Mbps */ , 0); /* send some multicast data */ bytes = lc_channel_send(chan, data, sizeof data, 0); if (bytes == -1) { perror("lc_channel_send"); goto free_ctx; } printf("sent: '%s' (%zi bytes)\n", data, bytes); rc = EXIT_SUCCESS; free_ctx: /* free the Context. This also frees all Sockets, Channels, Routers etc. * created with that Context */ lc_ctx_free(lctx); return rc; } ``` ### multicast receiver program ``` /* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2025 Brett Sheffield */ /* Librecast receiver example */ #include int main(void) { char data[BUFSIZ] = {0}; ssize_t bytes; int rc = EXIT_FAILURE; /* pessimistic, aren't we? */ /* we start with a Librecast Context (lc_ctx_t) */ lc_ctx_t *lctx = lc_ctx_new(); if (!lctx) return rc; /* create a Librecast Socket (IPv6) */ lc_socket_t *sock = lc_socket_new(lctx); if (!sock) goto free_ctx; /* create a Librecast Channel */ lc_channel_t *chan = lc_channel_new(lctx, "my very first Librecast channel"); /* bind the Channel to the Socket */ lc_channel_bind(sock, chan); /* join the Channel or we won't receive any data */ lc_channel_join(chan); /* (optional) enable RaptorQ encoding (RFC6330) */ lc_channel_coding_set(chan, LC_CODE_FEC_RQ | LC_CODE_FEC_OTI); /* recv some multicast data */ bytes = lc_channel_recv(chan, data, sizeof data, 0); if (bytes == -1) goto free_ctx; printf("received: '%s' (%zi bytes)\n", data, bytes); rc = EXIT_SUCCESS; free_ctx: /* free the Context. This also frees all Sockets, Channels, Routers etc. * created with that Context */ lc_ctx_free(lctx); return rc; } ``` These programs can be found in the `examples/` directory of the Librecast source code. There is a lot more example code which exercises the various capabilities of Librecast in the `test/` directory. The source code for [lcagent](https://codeberg.org/librecast/lcagent) and [lcsync](https://codeberg.org/librecast/lcsync) also demonstrate some of what a Librecast program can do. We are planning a Librecast Programming Guide, but in the meantime, read the headers and man pages, look at the tests and examples, and if you get stuck, feel free to [ask](#contact). ## Contact Us One of the great things about Free/Open Source Software is that you can talk with the people who make it. A project like this is about community as well as code, so we want to make you feel welcome. That's why we have a [Code of Conduct](CODE_OF_CONDUCT.md) and [Contributing](CONTRIBUTING.md) guidelines. Please do take a moment to read them. There are several ways to get in touch with us. If you think you've found a bug, please see the [Bugs](#Bugs) section for how to report it. You can also use our bug tracker to suggest a feature, or to ask a question, especially if you think the answer to that question may be of interest to others. For anything else, pick one of the contact methods below. ### Email We have low-traffic mailing lists for [announcements](https://lists.sr.ht/~librecast/librecast-announce), general [discussion](https://lists.sr.ht/~librecast/librecast-discuss) related to the Librecast Project and [development](https://lists.sr.ht/~librecast/librecast-devel). In addition, you can contact: - [bugs@librecast.net](mailto:bugs@librecast.net) to report a bug - [coc@librecast.net](mailto:coc@librecast.net) for any questions related to [Code of Conduct](CODE_OF_CONDUCT.md) or to make a report - [security@librecast.net](mailto:security@librecast.net) for security reports ### Fediverse (Mastodon) Follow us on the Fediverse. We announce new releases and project updates on Mastodon. You can find us here: [@librecast@chaos.social](https://chaos.social/@librecast). A huge thanks to Leah and rixx for hosting our project on chaos.social and for providing a stable and well moderated home for our community. ### IRC channel `#librecast` on irc.libera.chat If you have a question, please be patient. An answer might take a few hours depending on time zones and whether anyone on the team is available at that moment. We're always connected, so we'll notice eventually. Thanks to the Libera.Chat team for hosting our IRC channels. ### Matrix We have a [Librecast Matrix Room](https://matrix.to/#/#librecast:matrix.org). ## Code of Conduct See [Code of Conduct](CODE_OF_CONDUCT.md). ## Contributing See [Contributing](CONTRIBUTING.md). ## Bugs (also Questions and Feature Requests) New issues can be raised at: https://bugs.librecast.net/librecast It's okay to raise an issue to ask a question. You can also email or ask on IRC. See [Contact Us](#contact-us).

This project was funded through the NGI Zero Discovery, NGI Assure and NGI Zero Core funds, established by NLnet with financial support from the European Commission's Next Generation Internet programme. *See the NLnet open calls page to apply for funding for your project*

Logo NLnet: abstract logo of four people seen from above NGI Core Logo

librecast/config.guess000066400000000000000000001412021502456746400153600ustar00rootroot00000000000000#! /bin/sh # Attempt to guess a canonical system name. # Copyright 1992-2022 Free Software Foundation, Inc. # shellcheck disable=SC2006,SC2268 # see below for rationale timestamp='2022-05-25' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 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 . # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that # program. This Exception is an additional permission under section 7 # of the GNU General Public License, version 3 ("GPLv3"). # # Originally written by Per Bothner; maintained since 2000 by Ben Elliston. # # You can get the latest version of this script from: # https://git.savannah.gnu.org/cgit/config.git/plain/config.guess # # Please send patches to . # The "shellcheck disable" line above the timestamp inhibits complaints # about features and limitations of the classic Bourne shell that were # superseded or lifted in POSIX. However, this script identifies a wide # variety of pre-POSIX systems that do not have POSIX shells at all, and # even some reasonably current systems (Solaris 10 as case-in-point) still # have a pre-POSIX /bin/sh. me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] Output the configuration name of the system \`$me' is run on. Options: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.guess ($timestamp) Originally written by Per Bothner. Copyright 1992-2022 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit ;; --version | -v ) echo "$version" ; exit ;; --help | --h* | -h ) echo "$usage"; exit ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" >&2 exit 1 ;; * ) break ;; esac done if test $# != 0; then echo "$me: too many arguments$help" >&2 exit 1 fi # Just in case it came from the environment. GUESS= # CC_FOR_BUILD -- compiler used by this script. Note that the use of a # compiler to aid in system detection is discouraged as it requires # temporary files to be created and, as you can see below, it is a # headache to deal with in a portable fashion. # Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still # use `HOST_CC' if defined, but it is deprecated. # Portable tmp directory creation inspired by the Autoconf team. tmp= # shellcheck disable=SC2172 trap 'test -z "$tmp" || rm -fr "$tmp"' 0 1 2 13 15 set_cc_for_build() { # prevent multiple calls if $tmp is already set test "$tmp" && return 0 : "${TMPDIR=/tmp}" # shellcheck disable=SC2039,SC3028 { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir "$tmp" 2>/dev/null) ; } || { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir "$tmp" 2>/dev/null) && echo "Warning: creating insecure temp directory" >&2 ; } || { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } dummy=$tmp/dummy case ${CC_FOR_BUILD-},${HOST_CC-},${CC-} in ,,) echo "int x;" > "$dummy.c" for driver in cc gcc c89 c99 ; do if ($driver -c -o "$dummy.o" "$dummy.c") >/dev/null 2>&1 ; then CC_FOR_BUILD=$driver break fi done if test x"$CC_FOR_BUILD" = x ; then CC_FOR_BUILD=no_compiler_found fi ;; ,,*) CC_FOR_BUILD=$CC ;; ,*,*) CC_FOR_BUILD=$HOST_CC ;; esac } # This is needed to find uname on a Pyramid OSx when run in the BSD universe. # (ghazi@noc.rutgers.edu 1994-08-24) if test -f /.attbin/uname ; then PATH=$PATH:/.attbin ; export PATH fi UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown case $UNAME_SYSTEM in Linux|GNU|GNU/*) LIBC=unknown set_cc_for_build cat <<-EOF > "$dummy.c" #include #if defined(__UCLIBC__) LIBC=uclibc #elif defined(__dietlibc__) LIBC=dietlibc #elif defined(__GLIBC__) LIBC=gnu #else #include /* First heuristic to detect musl libc. */ #ifdef __DEFINED_va_list LIBC=musl #endif #endif EOF cc_set_libc=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^LIBC' | sed 's, ,,g'` eval "$cc_set_libc" # Second heuristic to detect musl libc. if [ "$LIBC" = unknown ] && command -v ldd >/dev/null && ldd --version 2>&1 | grep -q ^musl; then LIBC=musl fi # If the system lacks a compiler, then just pick glibc. # We could probably try harder. if [ "$LIBC" = unknown ]; then LIBC=gnu fi ;; esac # Note: order is significant - the case branches are not exclusive. case $UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION in *:NetBSD:*:*) # NetBSD (nbsd) targets should (where applicable) match one or # more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*, # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently # switched to ELF, *-*-netbsd* would select the old # object file format. This provides both forward # compatibility and a consistent mechanism for selecting the # object file format. # # Note: NetBSD doesn't particularly care about the vendor # portion of the name. We always set it to "unknown". UNAME_MACHINE_ARCH=`(uname -p 2>/dev/null || \ /sbin/sysctl -n hw.machine_arch 2>/dev/null || \ /usr/sbin/sysctl -n hw.machine_arch 2>/dev/null || \ echo unknown)` case $UNAME_MACHINE_ARCH in aarch64eb) machine=aarch64_be-unknown ;; armeb) machine=armeb-unknown ;; arm*) machine=arm-unknown ;; sh3el) machine=shl-unknown ;; sh3eb) machine=sh-unknown ;; sh5el) machine=sh5le-unknown ;; earmv*) arch=`echo "$UNAME_MACHINE_ARCH" | sed -e 's,^e\(armv[0-9]\).*$,\1,'` endian=`echo "$UNAME_MACHINE_ARCH" | sed -ne 's,^.*\(eb\)$,\1,p'` machine=${arch}${endian}-unknown ;; *) machine=$UNAME_MACHINE_ARCH-unknown ;; esac # The Operating System including object format, if it has switched # to ELF recently (or will in the future) and ABI. case $UNAME_MACHINE_ARCH in earm*) os=netbsdelf ;; arm*|i386|m68k|ns32k|sh3*|sparc|vax) set_cc_for_build if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ELF__ then # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). # Return netbsd for either. FIX? os=netbsd else os=netbsdelf fi ;; *) os=netbsd ;; esac # Determine ABI tags. case $UNAME_MACHINE_ARCH in earm*) expr='s/^earmv[0-9]/-eabi/;s/eb$//' abi=`echo "$UNAME_MACHINE_ARCH" | sed -e "$expr"` ;; esac # The OS release # Debian GNU/NetBSD machines have a different userland, and # thus, need a distinct triplet. However, they do not need # kernel version information, so it can be replaced with a # suitable tag, in the style of linux-gnu. case $UNAME_VERSION in Debian*) release='-gnu' ;; *) release=`echo "$UNAME_RELEASE" | sed -e 's/[-_].*//' | cut -d. -f1,2` ;; esac # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: # contains redundant information, the shorter form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. GUESS=$machine-${os}${release}${abi-} ;; *:Bitrig:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'` GUESS=$UNAME_MACHINE_ARCH-unknown-bitrig$UNAME_RELEASE ;; *:OpenBSD:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` GUESS=$UNAME_MACHINE_ARCH-unknown-openbsd$UNAME_RELEASE ;; *:SecBSD:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/SecBSD.//'` GUESS=$UNAME_MACHINE_ARCH-unknown-secbsd$UNAME_RELEASE ;; *:LibertyBSD:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/^.*BSD\.//'` GUESS=$UNAME_MACHINE_ARCH-unknown-libertybsd$UNAME_RELEASE ;; *:MidnightBSD:*:*) GUESS=$UNAME_MACHINE-unknown-midnightbsd$UNAME_RELEASE ;; *:ekkoBSD:*:*) GUESS=$UNAME_MACHINE-unknown-ekkobsd$UNAME_RELEASE ;; *:SolidBSD:*:*) GUESS=$UNAME_MACHINE-unknown-solidbsd$UNAME_RELEASE ;; *:OS108:*:*) GUESS=$UNAME_MACHINE-unknown-os108_$UNAME_RELEASE ;; macppc:MirBSD:*:*) GUESS=powerpc-unknown-mirbsd$UNAME_RELEASE ;; *:MirBSD:*:*) GUESS=$UNAME_MACHINE-unknown-mirbsd$UNAME_RELEASE ;; *:Sortix:*:*) GUESS=$UNAME_MACHINE-unknown-sortix ;; *:Twizzler:*:*) GUESS=$UNAME_MACHINE-unknown-twizzler ;; *:Redox:*:*) GUESS=$UNAME_MACHINE-unknown-redox ;; mips:OSF1:*.*) GUESS=mips-dec-osf1 ;; alpha:OSF1:*:*) # Reset EXIT trap before exiting to avoid spurious non-zero exit code. trap '' 0 case $UNAME_RELEASE in *4.0) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` ;; *5.*) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` ;; esac # According to Compaq, /usr/sbin/psrinfo has been available on # OSF/1 and Tru64 systems produced since 1995. I hope that # covers most systems running today. This code pipes the CPU # types through head -n 1, so we only detect the type of CPU 0. ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` case $ALPHA_CPU_TYPE in "EV4 (21064)") UNAME_MACHINE=alpha ;; "EV4.5 (21064)") UNAME_MACHINE=alpha ;; "LCA4 (21066/21068)") UNAME_MACHINE=alpha ;; "EV5 (21164)") UNAME_MACHINE=alphaev5 ;; "EV5.6 (21164A)") UNAME_MACHINE=alphaev56 ;; "EV5.6 (21164PC)") UNAME_MACHINE=alphapca56 ;; "EV5.7 (21164PC)") UNAME_MACHINE=alphapca57 ;; "EV6 (21264)") UNAME_MACHINE=alphaev6 ;; "EV6.7 (21264A)") UNAME_MACHINE=alphaev67 ;; "EV6.8CB (21264C)") UNAME_MACHINE=alphaev68 ;; "EV6.8AL (21264B)") UNAME_MACHINE=alphaev68 ;; "EV6.8CX (21264D)") UNAME_MACHINE=alphaev68 ;; "EV6.9A (21264/EV69A)") UNAME_MACHINE=alphaev69 ;; "EV7 (21364)") UNAME_MACHINE=alphaev7 ;; "EV7.9 (21364A)") UNAME_MACHINE=alphaev79 ;; esac # A Pn.n version is a patched version. # A Vn.n version is a released version. # A Tn.n version is a released field test version. # A Xn.n version is an unreleased experimental baselevel. # 1.2 uses "1.2" for uname -r. OSF_REL=`echo "$UNAME_RELEASE" | sed -e 's/^[PVTX]//' | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz` GUESS=$UNAME_MACHINE-dec-osf$OSF_REL ;; Amiga*:UNIX_System_V:4.0:*) GUESS=m68k-unknown-sysv4 ;; *:[Aa]miga[Oo][Ss]:*:*) GUESS=$UNAME_MACHINE-unknown-amigaos ;; *:[Mm]orph[Oo][Ss]:*:*) GUESS=$UNAME_MACHINE-unknown-morphos ;; *:OS/390:*:*) GUESS=i370-ibm-openedition ;; *:z/VM:*:*) GUESS=s390-ibm-zvmoe ;; *:OS400:*:*) GUESS=powerpc-ibm-os400 ;; arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) GUESS=arm-acorn-riscix$UNAME_RELEASE ;; arm*:riscos:*:*|arm*:RISCOS:*:*) GUESS=arm-unknown-riscos ;; SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) GUESS=hppa1.1-hitachi-hiuxmpp ;; Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. case `(/bin/universe) 2>/dev/null` in att) GUESS=pyramid-pyramid-sysv3 ;; *) GUESS=pyramid-pyramid-bsd ;; esac ;; NILE*:*:*:dcosx) GUESS=pyramid-pyramid-svr4 ;; DRS?6000:unix:4.0:6*) GUESS=sparc-icl-nx6 ;; DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) case `/usr/bin/uname -p` in sparc) GUESS=sparc-icl-nx7 ;; esac ;; s390x:SunOS:*:*) SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` GUESS=$UNAME_MACHINE-ibm-solaris2$SUN_REL ;; sun4H:SunOS:5.*:*) SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` GUESS=sparc-hal-solaris2$SUN_REL ;; sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` GUESS=sparc-sun-solaris2$SUN_REL ;; i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*) GUESS=i386-pc-auroraux$UNAME_RELEASE ;; i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) set_cc_for_build SUN_ARCH=i386 # If there is a compiler, see if it is configured for 64-bit objects. # Note that the Sun cc does not turn __LP64__ into 1 like gcc does. # This test works for both compilers. if test "$CC_FOR_BUILD" != no_compiler_found; then if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \ (CCOPTS="" $CC_FOR_BUILD -m64 -E - 2>/dev/null) | \ grep IS_64BIT_ARCH >/dev/null then SUN_ARCH=x86_64 fi fi SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` GUESS=$SUN_ARCH-pc-solaris2$SUN_REL ;; sun4*:SunOS:6*:*) # According to config.sub, this is the proper way to canonicalize # SunOS6. Hard to guess exactly what SunOS6 will be like, but # it's likely to be more like Solaris than SunOS4. SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` GUESS=sparc-sun-solaris3$SUN_REL ;; sun4*:SunOS:*:*) case `/usr/bin/arch -k` in Series*|S4*) UNAME_RELEASE=`uname -v` ;; esac # Japanese Language versions have a version number like `4.1.3-JL'. SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/-/_/'` GUESS=sparc-sun-sunos$SUN_REL ;; sun3*:SunOS:*:*) GUESS=m68k-sun-sunos$UNAME_RELEASE ;; sun*:*:4.2BSD:*) UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` test "x$UNAME_RELEASE" = x && UNAME_RELEASE=3 case `/bin/arch` in sun3) GUESS=m68k-sun-sunos$UNAME_RELEASE ;; sun4) GUESS=sparc-sun-sunos$UNAME_RELEASE ;; esac ;; aushp:SunOS:*:*) GUESS=sparc-auspex-sunos$UNAME_RELEASE ;; # The situation for MiNT is a little confusing. The machine name # can be virtually everything (everything which is not # "atarist" or "atariste" at least should have a processor # > m68000). The system name ranges from "MiNT" over "FreeMiNT" # to the lowercase version "mint" (or "freemint"). Finally # the system name "TOS" denotes a system which is actually not # MiNT. But MiNT is downward compatible to TOS, so this should # be no problem. atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) GUESS=m68k-atari-mint$UNAME_RELEASE ;; atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) GUESS=m68k-atari-mint$UNAME_RELEASE ;; *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) GUESS=m68k-atari-mint$UNAME_RELEASE ;; milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) GUESS=m68k-milan-mint$UNAME_RELEASE ;; hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) GUESS=m68k-hades-mint$UNAME_RELEASE ;; *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) GUESS=m68k-unknown-mint$UNAME_RELEASE ;; m68k:machten:*:*) GUESS=m68k-apple-machten$UNAME_RELEASE ;; powerpc:machten:*:*) GUESS=powerpc-apple-machten$UNAME_RELEASE ;; RISC*:Mach:*:*) GUESS=mips-dec-mach_bsd4.3 ;; RISC*:ULTRIX:*:*) GUESS=mips-dec-ultrix$UNAME_RELEASE ;; VAX*:ULTRIX*:*:*) GUESS=vax-dec-ultrix$UNAME_RELEASE ;; 2020:CLIX:*:* | 2430:CLIX:*:*) GUESS=clipper-intergraph-clix$UNAME_RELEASE ;; mips:*:*:UMIPS | mips:*:*:RISCos) set_cc_for_build sed 's/^ //' << EOF > "$dummy.c" #ifdef __cplusplus #include /* for printf() prototype */ int main (int argc, char *argv[]) { #else int main (argc, argv) int argc; char *argv[]; { #endif #if defined (host_mips) && defined (MIPSEB) #if defined (SYSTYPE_SYSV) printf ("mips-mips-riscos%ssysv\\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_SVR4) printf ("mips-mips-riscos%ssvr4\\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) printf ("mips-mips-riscos%sbsd\\n", argv[1]); exit (0); #endif #endif exit (-1); } EOF $CC_FOR_BUILD -o "$dummy" "$dummy.c" && dummyarg=`echo "$UNAME_RELEASE" | sed -n 's/\([0-9]*\).*/\1/p'` && SYSTEM_NAME=`"$dummy" "$dummyarg"` && { echo "$SYSTEM_NAME"; exit; } GUESS=mips-mips-riscos$UNAME_RELEASE ;; Motorola:PowerMAX_OS:*:*) GUESS=powerpc-motorola-powermax ;; Motorola:*:4.3:PL8-*) GUESS=powerpc-harris-powermax ;; Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) GUESS=powerpc-harris-powermax ;; Night_Hawk:Power_UNIX:*:*) GUESS=powerpc-harris-powerunix ;; m88k:CX/UX:7*:*) GUESS=m88k-harris-cxux7 ;; m88k:*:4*:R4*) GUESS=m88k-motorola-sysv4 ;; m88k:*:3*:R3*) GUESS=m88k-motorola-sysv3 ;; AViiON:dgux:*:*) # DG/UX returns AViiON for all architectures UNAME_PROCESSOR=`/usr/bin/uname -p` if test "$UNAME_PROCESSOR" = mc88100 || test "$UNAME_PROCESSOR" = mc88110 then if test "$TARGET_BINARY_INTERFACE"x = m88kdguxelfx || \ test "$TARGET_BINARY_INTERFACE"x = x then GUESS=m88k-dg-dgux$UNAME_RELEASE else GUESS=m88k-dg-dguxbcs$UNAME_RELEASE fi else GUESS=i586-dg-dgux$UNAME_RELEASE fi ;; M88*:DolphinOS:*:*) # DolphinOS (SVR3) GUESS=m88k-dolphin-sysv3 ;; M88*:*:R3*:*) # Delta 88k system running SVR3 GUESS=m88k-motorola-sysv3 ;; XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) GUESS=m88k-tektronix-sysv3 ;; Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) GUESS=m68k-tektronix-bsd ;; *:IRIX*:*:*) IRIX_REL=`echo "$UNAME_RELEASE" | sed -e 's/-/_/g'` GUESS=mips-sgi-irix$IRIX_REL ;; ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. GUESS=romp-ibm-aix # uname -m gives an 8 hex-code CPU id ;; # Note that: echo "'`uname -s`'" gives 'AIX ' i*86:AIX:*:*) GUESS=i386-ibm-aix ;; ia64:AIX:*:*) if test -x /usr/bin/oslevel ; then IBM_REV=`/usr/bin/oslevel` else IBM_REV=$UNAME_VERSION.$UNAME_RELEASE fi GUESS=$UNAME_MACHINE-ibm-aix$IBM_REV ;; *:AIX:2:3) if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then set_cc_for_build sed 's/^ //' << EOF > "$dummy.c" #include main() { if (!__power_pc()) exit(1); puts("powerpc-ibm-aix3.2.5"); exit(0); } EOF if $CC_FOR_BUILD -o "$dummy" "$dummy.c" && SYSTEM_NAME=`"$dummy"` then GUESS=$SYSTEM_NAME else GUESS=rs6000-ibm-aix3.2.5 fi elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then GUESS=rs6000-ibm-aix3.2.4 else GUESS=rs6000-ibm-aix3.2 fi ;; *:AIX:*:[4567]) IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` if /usr/sbin/lsattr -El "$IBM_CPU_ID" | grep ' POWER' >/dev/null 2>&1; then IBM_ARCH=rs6000 else IBM_ARCH=powerpc fi if test -x /usr/bin/lslpp ; then IBM_REV=`/usr/bin/lslpp -Lqc bos.rte.libc | \ awk -F: '{ print $3 }' | sed s/[0-9]*$/0/` else IBM_REV=$UNAME_VERSION.$UNAME_RELEASE fi GUESS=$IBM_ARCH-ibm-aix$IBM_REV ;; *:AIX:*:*) GUESS=rs6000-ibm-aix ;; ibmrt:4.4BSD:*|romp-ibm:4.4BSD:*) GUESS=romp-ibm-bsd4.4 ;; ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and GUESS=romp-ibm-bsd$UNAME_RELEASE # 4.3 with uname added to ;; # report: romp-ibm BSD 4.3 *:BOSX:*:*) GUESS=rs6000-bull-bosx ;; DPX/2?00:B.O.S.:*:*) GUESS=m68k-bull-sysv3 ;; 9000/[34]??:4.3bsd:1.*:*) GUESS=m68k-hp-bsd ;; hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) GUESS=m68k-hp-bsd4.4 ;; 9000/[34678]??:HP-UX:*:*) HPUX_REV=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*.[0B]*//'` case $UNAME_MACHINE in 9000/31?) HP_ARCH=m68000 ;; 9000/[34]??) HP_ARCH=m68k ;; 9000/[678][0-9][0-9]) if test -x /usr/bin/getconf; then sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` case $sc_cpu_version in 523) HP_ARCH=hppa1.0 ;; # CPU_PA_RISC1_0 528) HP_ARCH=hppa1.1 ;; # CPU_PA_RISC1_1 532) # CPU_PA_RISC2_0 case $sc_kernel_bits in 32) HP_ARCH=hppa2.0n ;; 64) HP_ARCH=hppa2.0w ;; '') HP_ARCH=hppa2.0 ;; # HP-UX 10.20 esac ;; esac fi if test "$HP_ARCH" = ""; then set_cc_for_build sed 's/^ //' << EOF > "$dummy.c" #define _HPUX_SOURCE #include #include int main () { #if defined(_SC_KERNEL_BITS) long bits = sysconf(_SC_KERNEL_BITS); #endif long cpu = sysconf (_SC_CPU_VERSION); switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0"); break; case CPU_PA_RISC1_1: puts ("hppa1.1"); break; case CPU_PA_RISC2_0: #if defined(_SC_KERNEL_BITS) switch (bits) { case 64: puts ("hppa2.0w"); break; case 32: puts ("hppa2.0n"); break; default: puts ("hppa2.0"); break; } break; #else /* !defined(_SC_KERNEL_BITS) */ puts ("hppa2.0"); break; #endif default: puts ("hppa1.0"); break; } exit (0); } EOF (CCOPTS="" $CC_FOR_BUILD -o "$dummy" "$dummy.c" 2>/dev/null) && HP_ARCH=`"$dummy"` test -z "$HP_ARCH" && HP_ARCH=hppa fi ;; esac if test "$HP_ARCH" = hppa2.0w then set_cc_for_build # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler # generating 64-bit code. GNU and HP use different nomenclature: # # $ CC_FOR_BUILD=cc ./config.guess # => hppa2.0w-hp-hpux11.23 # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess # => hppa64-hp-hpux11.23 if echo __LP64__ | (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | grep -q __LP64__ then HP_ARCH=hppa2.0w else HP_ARCH=hppa64 fi fi GUESS=$HP_ARCH-hp-hpux$HPUX_REV ;; ia64:HP-UX:*:*) HPUX_REV=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*.[0B]*//'` GUESS=ia64-hp-hpux$HPUX_REV ;; 3050*:HI-UX:*:*) set_cc_for_build sed 's/^ //' << EOF > "$dummy.c" #include int main () { long cpu = sysconf (_SC_CPU_VERSION); /* The order matters, because CPU_IS_HP_MC68K erroneously returns true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct results, however. */ if (CPU_IS_PA_RISC (cpu)) { switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; default: puts ("hppa-hitachi-hiuxwe2"); break; } } else if (CPU_IS_HP_MC68K (cpu)) puts ("m68k-hitachi-hiuxwe2"); else puts ("unknown-hitachi-hiuxwe2"); exit (0); } EOF $CC_FOR_BUILD -o "$dummy" "$dummy.c" && SYSTEM_NAME=`"$dummy"` && { echo "$SYSTEM_NAME"; exit; } GUESS=unknown-hitachi-hiuxwe2 ;; 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:*) GUESS=hppa1.1-hp-bsd ;; 9000/8??:4.3bsd:*:*) GUESS=hppa1.0-hp-bsd ;; *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) GUESS=hppa1.0-hp-mpeix ;; hp7??:OSF1:*:* | hp8?[79]:OSF1:*:*) GUESS=hppa1.1-hp-osf ;; hp8??:OSF1:*:*) GUESS=hppa1.0-hp-osf ;; i*86:OSF1:*:*) if test -x /usr/sbin/sysversion ; then GUESS=$UNAME_MACHINE-unknown-osf1mk else GUESS=$UNAME_MACHINE-unknown-osf1 fi ;; parisc*:Lites*:*:*) GUESS=hppa1.1-hp-lites ;; C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) GUESS=c1-convex-bsd ;; C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi exit ;; C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) GUESS=c34-convex-bsd ;; C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) GUESS=c38-convex-bsd ;; C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) GUESS=c4-convex-bsd ;; CRAY*Y-MP:*:*:*) CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'` GUESS=ymp-cray-unicos$CRAY_REL ;; CRAY*[A-Z]90:*:*:*) echo "$UNAME_MACHINE"-cray-unicos"$UNAME_RELEASE" \ | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ -e 's/\.[^.]*$/.X/' exit ;; CRAY*TS:*:*:*) CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'` GUESS=t90-cray-unicos$CRAY_REL ;; CRAY*T3E:*:*:*) CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'` GUESS=alphaev5-cray-unicosmk$CRAY_REL ;; CRAY*SV1:*:*:*) CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'` GUESS=sv1-cray-unicos$CRAY_REL ;; *:UNICOS/mp:*:*) CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'` GUESS=craynv-cray-unicosmp$CRAY_REL ;; F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) FUJITSU_PROC=`uname -m | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz` FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'` FUJITSU_REL=`echo "$UNAME_RELEASE" | sed -e 's/ /_/'` GUESS=${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL} ;; 5000:UNIX_System_V:4.*:*) FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'` FUJITSU_REL=`echo "$UNAME_RELEASE" | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/ /_/'` GUESS=sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL} ;; i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) GUESS=$UNAME_MACHINE-pc-bsdi$UNAME_RELEASE ;; sparc*:BSD/OS:*:*) GUESS=sparc-unknown-bsdi$UNAME_RELEASE ;; *:BSD/OS:*:*) GUESS=$UNAME_MACHINE-unknown-bsdi$UNAME_RELEASE ;; arm:FreeBSD:*:*) UNAME_PROCESSOR=`uname -p` set_cc_for_build if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_PCS_VFP then FREEBSD_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'` GUESS=$UNAME_PROCESSOR-unknown-freebsd$FREEBSD_REL-gnueabi else FREEBSD_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'` GUESS=$UNAME_PROCESSOR-unknown-freebsd$FREEBSD_REL-gnueabihf fi ;; *:FreeBSD:*:*) UNAME_PROCESSOR=`/usr/bin/uname -p` case $UNAME_PROCESSOR in amd64) UNAME_PROCESSOR=x86_64 ;; i386) UNAME_PROCESSOR=i586 ;; esac FREEBSD_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'` GUESS=$UNAME_PROCESSOR-unknown-freebsd$FREEBSD_REL ;; i*:CYGWIN*:*) GUESS=$UNAME_MACHINE-pc-cygwin ;; *:MINGW64*:*) GUESS=$UNAME_MACHINE-pc-mingw64 ;; *:MINGW*:*) GUESS=$UNAME_MACHINE-pc-mingw32 ;; *:MSYS*:*) GUESS=$UNAME_MACHINE-pc-msys ;; i*:PW*:*) GUESS=$UNAME_MACHINE-pc-pw32 ;; *:SerenityOS:*:*) GUESS=$UNAME_MACHINE-pc-serenity ;; *:Interix*:*) case $UNAME_MACHINE in x86) GUESS=i586-pc-interix$UNAME_RELEASE ;; authenticamd | genuineintel | EM64T) GUESS=x86_64-unknown-interix$UNAME_RELEASE ;; IA64) GUESS=ia64-unknown-interix$UNAME_RELEASE ;; esac ;; i*:UWIN*:*) GUESS=$UNAME_MACHINE-pc-uwin ;; amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) GUESS=x86_64-pc-cygwin ;; prep*:SunOS:5.*:*) SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` GUESS=powerpcle-unknown-solaris2$SUN_REL ;; *:GNU:*:*) # the GNU system GNU_ARCH=`echo "$UNAME_MACHINE" | sed -e 's,[-/].*$,,'` GNU_REL=`echo "$UNAME_RELEASE" | sed -e 's,/.*$,,'` GUESS=$GNU_ARCH-unknown-$LIBC$GNU_REL ;; *:GNU/*:*:*) # other systems with GNU libc and userland GNU_SYS=`echo "$UNAME_SYSTEM" | sed 's,^[^/]*/,,' | tr "[:upper:]" "[:lower:]"` GNU_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'` GUESS=$UNAME_MACHINE-unknown-$GNU_SYS$GNU_REL-$LIBC ;; *:Minix:*:*) GUESS=$UNAME_MACHINE-unknown-minix ;; aarch64:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; aarch64_be:Linux:*:*) UNAME_MACHINE=aarch64_be GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; alpha:Linux:*:*) case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' /proc/cpuinfo 2>/dev/null` in EV5) UNAME_MACHINE=alphaev5 ;; EV56) UNAME_MACHINE=alphaev56 ;; PCA56) UNAME_MACHINE=alphapca56 ;; PCA57) UNAME_MACHINE=alphapca56 ;; EV6) UNAME_MACHINE=alphaev6 ;; EV67) UNAME_MACHINE=alphaev67 ;; EV68*) UNAME_MACHINE=alphaev68 ;; esac objdump --private-headers /bin/sh | grep -q ld.so.1 if test "$?" = 0 ; then LIBC=gnulibc1 ; fi GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; arc:Linux:*:* | arceb:Linux:*:* | arc32:Linux:*:* | arc64:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; arm*:Linux:*:*) set_cc_for_build if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_EABI__ then GUESS=$UNAME_MACHINE-unknown-linux-$LIBC else if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_PCS_VFP then GUESS=$UNAME_MACHINE-unknown-linux-${LIBC}eabi else GUESS=$UNAME_MACHINE-unknown-linux-${LIBC}eabihf fi fi ;; avr32*:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; cris:Linux:*:*) GUESS=$UNAME_MACHINE-axis-linux-$LIBC ;; crisv32:Linux:*:*) GUESS=$UNAME_MACHINE-axis-linux-$LIBC ;; e2k:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; frv:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; hexagon:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; i*86:Linux:*:*) GUESS=$UNAME_MACHINE-pc-linux-$LIBC ;; ia64:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; k1om:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; loongarch32:Linux:*:* | loongarch64:Linux:*:* | loongarchx32:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; m32r*:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; m68*:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; mips:Linux:*:* | mips64:Linux:*:*) set_cc_for_build IS_GLIBC=0 test x"${LIBC}" = xgnu && IS_GLIBC=1 sed 's/^ //' << EOF > "$dummy.c" #undef CPU #undef mips #undef mipsel #undef mips64 #undef mips64el #if ${IS_GLIBC} && defined(_ABI64) LIBCABI=gnuabi64 #else #if ${IS_GLIBC} && defined(_ABIN32) LIBCABI=gnuabin32 #else LIBCABI=${LIBC} #endif #endif #if ${IS_GLIBC} && defined(__mips64) && defined(__mips_isa_rev) && __mips_isa_rev>=6 CPU=mipsisa64r6 #else #if ${IS_GLIBC} && !defined(__mips64) && defined(__mips_isa_rev) && __mips_isa_rev>=6 CPU=mipsisa32r6 #else #if defined(__mips64) CPU=mips64 #else CPU=mips #endif #endif #endif #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) MIPS_ENDIAN=el #else #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) MIPS_ENDIAN= #else MIPS_ENDIAN= #endif #endif EOF cc_set_vars=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^CPU\|^MIPS_ENDIAN\|^LIBCABI'` eval "$cc_set_vars" test "x$CPU" != x && { echo "$CPU${MIPS_ENDIAN}-unknown-linux-$LIBCABI"; exit; } ;; mips64el:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; openrisc*:Linux:*:*) GUESS=or1k-unknown-linux-$LIBC ;; or32:Linux:*:* | or1k*:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; padre:Linux:*:*) GUESS=sparc-unknown-linux-$LIBC ;; parisc64:Linux:*:* | hppa64:Linux:*:*) GUESS=hppa64-unknown-linux-$LIBC ;; parisc:Linux:*:* | hppa:Linux:*:*) # Look for CPU level case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in PA7*) GUESS=hppa1.1-unknown-linux-$LIBC ;; PA8*) GUESS=hppa2.0-unknown-linux-$LIBC ;; *) GUESS=hppa-unknown-linux-$LIBC ;; esac ;; ppc64:Linux:*:*) GUESS=powerpc64-unknown-linux-$LIBC ;; ppc:Linux:*:*) GUESS=powerpc-unknown-linux-$LIBC ;; ppc64le:Linux:*:*) GUESS=powerpc64le-unknown-linux-$LIBC ;; ppcle:Linux:*:*) GUESS=powerpcle-unknown-linux-$LIBC ;; riscv32:Linux:*:* | riscv32be:Linux:*:* | riscv64:Linux:*:* | riscv64be:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; s390:Linux:*:* | s390x:Linux:*:*) GUESS=$UNAME_MACHINE-ibm-linux-$LIBC ;; sh64*:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; sh*:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; sparc:Linux:*:* | sparc64:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; tile*:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; vax:Linux:*:*) GUESS=$UNAME_MACHINE-dec-linux-$LIBC ;; x86_64:Linux:*:*) set_cc_for_build CPU=$UNAME_MACHINE LIBCABI=$LIBC if test "$CC_FOR_BUILD" != no_compiler_found; then ABI=64 sed 's/^ //' << EOF > "$dummy.c" #ifdef __i386__ ABI=x86 #else #ifdef __ILP32__ ABI=x32 #endif #endif EOF cc_set_abi=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^ABI' | sed 's, ,,g'` eval "$cc_set_abi" case $ABI in x86) CPU=i686 ;; x32) LIBCABI=${LIBC}x32 ;; esac fi GUESS=$CPU-pc-linux-$LIBCABI ;; xtensa*:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; i*86:DYNIX/ptx:4*:*) # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. # earlier versions are messed up and put the nodename in both # sysname and nodename. GUESS=i386-sequent-sysv4 ;; i*86:UNIX_SV:4.2MP:2.*) # Unixware is an offshoot of SVR4, but it has its own version # number series starting with 2... # I am not positive that other SVR4 systems won't match this, # I just have to hope. -- rms. # Use sysv4.2uw... so that sysv4* matches it. GUESS=$UNAME_MACHINE-pc-sysv4.2uw$UNAME_VERSION ;; i*86:OS/2:*:*) # If we were able to find `uname', then EMX Unix compatibility # is probably installed. GUESS=$UNAME_MACHINE-pc-os2-emx ;; i*86:XTS-300:*:STOP) GUESS=$UNAME_MACHINE-unknown-stop ;; i*86:atheos:*:*) GUESS=$UNAME_MACHINE-unknown-atheos ;; i*86:syllable:*:*) GUESS=$UNAME_MACHINE-pc-syllable ;; i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*) GUESS=i386-unknown-lynxos$UNAME_RELEASE ;; i*86:*DOS:*:*) GUESS=$UNAME_MACHINE-pc-msdosdjgpp ;; i*86:*:4.*:*) UNAME_REL=`echo "$UNAME_RELEASE" | sed 's/\/MP$//'` if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then GUESS=$UNAME_MACHINE-univel-sysv$UNAME_REL else GUESS=$UNAME_MACHINE-pc-sysv$UNAME_REL fi ;; i*86:*:5:[678]*) # UnixWare 7.x, OpenUNIX and OpenServer 6. case `/bin/uname -X | grep "^Machine"` in *486*) UNAME_MACHINE=i486 ;; *Pentium) UNAME_MACHINE=i586 ;; *Pent*|*Celeron) UNAME_MACHINE=i686 ;; esac GUESS=$UNAME_MACHINE-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} ;; i*86:*:3.2:*) if test -f /usr/options/cb.name; then UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ && UNAME_MACHINE=i586 (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ && UNAME_MACHINE=i686 (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ && UNAME_MACHINE=i686 GUESS=$UNAME_MACHINE-pc-sco$UNAME_REL else GUESS=$UNAME_MACHINE-pc-sysv32 fi ;; pc:*:*:*) # Left here for compatibility: # uname -m prints for DJGPP always 'pc', but it prints nothing about # the processor, so we play safe by assuming i586. # Note: whatever this is, it MUST be the same as what config.sub # prints for the "djgpp" host, or else GDB configure will decide that # this is a cross-build. GUESS=i586-pc-msdosdjgpp ;; Intel:Mach:3*:*) GUESS=i386-pc-mach3 ;; paragon:*:*:*) GUESS=i860-intel-osf1 ;; i860:*:4.*:*) # i860-SVR4 if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then GUESS=i860-stardent-sysv$UNAME_RELEASE # Stardent Vistra i860-SVR4 else # Add other i860-SVR4 vendors below as they are discovered. GUESS=i860-unknown-sysv$UNAME_RELEASE # Unknown i860-SVR4 fi ;; mini*:CTIX:SYS*5:*) # "miniframe" GUESS=m68010-convergent-sysv ;; mc68k:UNIX:SYSTEM5:3.51m) GUESS=m68k-convergent-sysv ;; M680?0:D-NIX:5.3:*) GUESS=m68k-diab-dnix ;; M68*:*:R3V[5678]*:*) test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) OS_REL='' test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4.3"$OS_REL"; exit; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && { echo i586-ncr-sysv4.3"$OS_REL"; exit; } ;; 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4; exit; } ;; NCR*:*:4.2:* | MPRAS*:*:4.2:*) OS_REL='.3' test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4.3"$OS_REL"; exit; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && { echo i586-ncr-sysv4.3"$OS_REL"; exit; } /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \ && { echo i586-ncr-sysv4.3"$OS_REL"; exit; } ;; m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) GUESS=m68k-unknown-lynxos$UNAME_RELEASE ;; mc68030:UNIX_System_V:4.*:*) GUESS=m68k-atari-sysv4 ;; TSUNAMI:LynxOS:2.*:*) GUESS=sparc-unknown-lynxos$UNAME_RELEASE ;; rs6000:LynxOS:2.*:*) GUESS=rs6000-unknown-lynxos$UNAME_RELEASE ;; PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*) GUESS=powerpc-unknown-lynxos$UNAME_RELEASE ;; SM[BE]S:UNIX_SV:*:*) GUESS=mips-dde-sysv$UNAME_RELEASE ;; RM*:ReliantUNIX-*:*:*) GUESS=mips-sni-sysv4 ;; RM*:SINIX-*:*:*) GUESS=mips-sni-sysv4 ;; *:SINIX-*:*:*) if uname -p 2>/dev/null >/dev/null ; then UNAME_MACHINE=`(uname -p) 2>/dev/null` GUESS=$UNAME_MACHINE-sni-sysv4 else GUESS=ns32k-sni-sysv fi ;; PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort # says GUESS=i586-unisys-sysv4 ;; *:UNIX_System_V:4*:FTX*) # From Gerald Hewes . # How about differentiating between stratus architectures? -djm GUESS=hppa1.1-stratus-sysv4 ;; *:*:*:FTX*) # From seanf@swdc.stratus.com. GUESS=i860-stratus-sysv4 ;; i*86:VOS:*:*) # From Paul.Green@stratus.com. GUESS=$UNAME_MACHINE-stratus-vos ;; *:VOS:*:*) # From Paul.Green@stratus.com. GUESS=hppa1.1-stratus-vos ;; mc68*:A/UX:*:*) GUESS=m68k-apple-aux$UNAME_RELEASE ;; news*:NEWS-OS:6*:*) GUESS=mips-sony-newsos6 ;; R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) if test -d /usr/nec; then GUESS=mips-nec-sysv$UNAME_RELEASE else GUESS=mips-unknown-sysv$UNAME_RELEASE fi ;; BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. GUESS=powerpc-be-beos ;; BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. GUESS=powerpc-apple-beos ;; BePC:BeOS:*:*) # BeOS running on Intel PC compatible. GUESS=i586-pc-beos ;; BePC:Haiku:*:*) # Haiku running on Intel PC compatible. GUESS=i586-pc-haiku ;; ppc:Haiku:*:*) # Haiku running on Apple PowerPC GUESS=powerpc-apple-haiku ;; *:Haiku:*:*) # Haiku modern gcc (not bound by BeOS compat) GUESS=$UNAME_MACHINE-unknown-haiku ;; SX-4:SUPER-UX:*:*) GUESS=sx4-nec-superux$UNAME_RELEASE ;; SX-5:SUPER-UX:*:*) GUESS=sx5-nec-superux$UNAME_RELEASE ;; SX-6:SUPER-UX:*:*) GUESS=sx6-nec-superux$UNAME_RELEASE ;; SX-7:SUPER-UX:*:*) GUESS=sx7-nec-superux$UNAME_RELEASE ;; SX-8:SUPER-UX:*:*) GUESS=sx8-nec-superux$UNAME_RELEASE ;; SX-8R:SUPER-UX:*:*) GUESS=sx8r-nec-superux$UNAME_RELEASE ;; SX-ACE:SUPER-UX:*:*) GUESS=sxace-nec-superux$UNAME_RELEASE ;; Power*:Rhapsody:*:*) GUESS=powerpc-apple-rhapsody$UNAME_RELEASE ;; *:Rhapsody:*:*) GUESS=$UNAME_MACHINE-apple-rhapsody$UNAME_RELEASE ;; arm64:Darwin:*:*) GUESS=aarch64-apple-darwin$UNAME_RELEASE ;; *:Darwin:*:*) UNAME_PROCESSOR=`uname -p` case $UNAME_PROCESSOR in unknown) UNAME_PROCESSOR=powerpc ;; esac if command -v xcode-select > /dev/null 2> /dev/null && \ ! xcode-select --print-path > /dev/null 2> /dev/null ; then # Avoid executing cc if there is no toolchain installed as # cc will be a stub that puts up a graphical alert # prompting the user to install developer tools. CC_FOR_BUILD=no_compiler_found else set_cc_for_build fi if test "$CC_FOR_BUILD" != no_compiler_found; then if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \ (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ grep IS_64BIT_ARCH >/dev/null then case $UNAME_PROCESSOR in i386) UNAME_PROCESSOR=x86_64 ;; powerpc) UNAME_PROCESSOR=powerpc64 ;; esac fi # On 10.4-10.6 one might compile for PowerPC via gcc -arch ppc if (echo '#ifdef __POWERPC__'; echo IS_PPC; echo '#endif') | \ (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ grep IS_PPC >/dev/null then UNAME_PROCESSOR=powerpc fi elif test "$UNAME_PROCESSOR" = i386 ; then # uname -m returns i386 or x86_64 UNAME_PROCESSOR=$UNAME_MACHINE fi GUESS=$UNAME_PROCESSOR-apple-darwin$UNAME_RELEASE ;; *:procnto*:*:* | *:QNX:[0123456789]*:*) UNAME_PROCESSOR=`uname -p` if test "$UNAME_PROCESSOR" = x86; then UNAME_PROCESSOR=i386 UNAME_MACHINE=pc fi GUESS=$UNAME_PROCESSOR-$UNAME_MACHINE-nto-qnx$UNAME_RELEASE ;; *:QNX:*:4*) GUESS=i386-pc-qnx ;; NEO-*:NONSTOP_KERNEL:*:*) GUESS=neo-tandem-nsk$UNAME_RELEASE ;; NSE-*:NONSTOP_KERNEL:*:*) GUESS=nse-tandem-nsk$UNAME_RELEASE ;; NSR-*:NONSTOP_KERNEL:*:*) GUESS=nsr-tandem-nsk$UNAME_RELEASE ;; NSV-*:NONSTOP_KERNEL:*:*) GUESS=nsv-tandem-nsk$UNAME_RELEASE ;; NSX-*:NONSTOP_KERNEL:*:*) GUESS=nsx-tandem-nsk$UNAME_RELEASE ;; *:NonStop-UX:*:*) GUESS=mips-compaq-nonstopux ;; BS2000:POSIX*:*:*) GUESS=bs2000-siemens-sysv ;; DS/*:UNIX_System_V:*:*) GUESS=$UNAME_MACHINE-$UNAME_SYSTEM-$UNAME_RELEASE ;; *:Plan9:*:*) # "uname -m" is not consistent, so use $cputype instead. 386 # is converted to i386 for consistency with other x86 # operating systems. if test "${cputype-}" = 386; then UNAME_MACHINE=i386 elif test "x${cputype-}" != x; then UNAME_MACHINE=$cputype fi GUESS=$UNAME_MACHINE-unknown-plan9 ;; *:TOPS-10:*:*) GUESS=pdp10-unknown-tops10 ;; *:TENEX:*:*) GUESS=pdp10-unknown-tenex ;; KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) GUESS=pdp10-dec-tops20 ;; XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) GUESS=pdp10-xkl-tops20 ;; *:TOPS-20:*:*) GUESS=pdp10-unknown-tops20 ;; *:ITS:*:*) GUESS=pdp10-unknown-its ;; SEI:*:*:SEIUX) GUESS=mips-sei-seiux$UNAME_RELEASE ;; *:DragonFly:*:*) DRAGONFLY_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'` GUESS=$UNAME_MACHINE-unknown-dragonfly$DRAGONFLY_REL ;; *:*VMS:*:*) UNAME_MACHINE=`(uname -p) 2>/dev/null` case $UNAME_MACHINE in A*) GUESS=alpha-dec-vms ;; I*) GUESS=ia64-dec-vms ;; V*) GUESS=vax-dec-vms ;; esac ;; *:XENIX:*:SysV) GUESS=i386-pc-xenix ;; i*86:skyos:*:*) SKYOS_REL=`echo "$UNAME_RELEASE" | sed -e 's/ .*$//'` GUESS=$UNAME_MACHINE-pc-skyos$SKYOS_REL ;; i*86:rdos:*:*) GUESS=$UNAME_MACHINE-pc-rdos ;; i*86:Fiwix:*:*) GUESS=$UNAME_MACHINE-pc-fiwix ;; *:AROS:*:*) GUESS=$UNAME_MACHINE-unknown-aros ;; x86_64:VMkernel:*:*) GUESS=$UNAME_MACHINE-unknown-esx ;; amd64:Isilon\ OneFS:*:*) GUESS=x86_64-unknown-onefs ;; *:Unleashed:*:*) GUESS=$UNAME_MACHINE-unknown-unleashed$UNAME_RELEASE ;; esac # Do we have a guess based on uname results? if test "x$GUESS" != x; then echo "$GUESS" exit fi # No uname command or uname output not recognized. set_cc_for_build cat > "$dummy.c" < #include #endif #if defined(ultrix) || defined(_ultrix) || defined(__ultrix) || defined(__ultrix__) #if defined (vax) || defined (__vax) || defined (__vax__) || defined(mips) || defined(__mips) || defined(__mips__) || defined(MIPS) || defined(__MIPS__) #include #if defined(_SIZE_T_) || defined(SIGLOST) #include #endif #endif #endif main () { #if defined (sony) #if defined (MIPSEB) /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, I don't know.... */ printf ("mips-sony-bsd\n"); exit (0); #else #include printf ("m68k-sony-newsos%s\n", #ifdef NEWSOS4 "4" #else "" #endif ); exit (0); #endif #endif #if defined (NeXT) #if !defined (__ARCHITECTURE__) #define __ARCHITECTURE__ "m68k" #endif int version; version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; if (version < 4) printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); else printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); exit (0); #endif #if defined (MULTIMAX) || defined (n16) #if defined (UMAXV) printf ("ns32k-encore-sysv\n"); exit (0); #else #if defined (CMU) printf ("ns32k-encore-mach\n"); exit (0); #else printf ("ns32k-encore-bsd\n"); exit (0); #endif #endif #endif #if defined (__386BSD__) printf ("i386-pc-bsd\n"); exit (0); #endif #if defined (sequent) #if defined (i386) printf ("i386-sequent-dynix\n"); exit (0); #endif #if defined (ns32000) printf ("ns32k-sequent-dynix\n"); exit (0); #endif #endif #if defined (_SEQUENT_) struct utsname un; uname(&un); if (strncmp(un.version, "V2", 2) == 0) { printf ("i386-sequent-ptx2\n"); exit (0); } if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ printf ("i386-sequent-ptx1\n"); exit (0); } printf ("i386-sequent-ptx\n"); exit (0); #endif #if defined (vax) #if !defined (ultrix) #include #if defined (BSD) #if BSD == 43 printf ("vax-dec-bsd4.3\n"); exit (0); #else #if BSD == 199006 printf ("vax-dec-bsd4.3reno\n"); exit (0); #else printf ("vax-dec-bsd\n"); exit (0); #endif #endif #else printf ("vax-dec-bsd\n"); exit (0); #endif #else #if defined(_SIZE_T_) || defined(SIGLOST) struct utsname un; uname (&un); printf ("vax-dec-ultrix%s\n", un.release); exit (0); #else printf ("vax-dec-ultrix\n"); exit (0); #endif #endif #endif #if defined(ultrix) || defined(_ultrix) || defined(__ultrix) || defined(__ultrix__) #if defined(mips) || defined(__mips) || defined(__mips__) || defined(MIPS) || defined(__MIPS__) #if defined(_SIZE_T_) || defined(SIGLOST) struct utsname *un; uname (&un); printf ("mips-dec-ultrix%s\n", un.release); exit (0); #else printf ("mips-dec-ultrix\n"); exit (0); #endif #endif #endif #if defined (alliant) && defined (i860) printf ("i860-alliant-bsd\n"); exit (0); #endif exit (1); } EOF $CC_FOR_BUILD -o "$dummy" "$dummy.c" 2>/dev/null && SYSTEM_NAME=`"$dummy"` && { echo "$SYSTEM_NAME"; exit; } # Apollos put the system type in the environment. test -d /usr/apollo && { echo "$ISP-apollo-$SYSTYPE"; exit; } echo "$0: unable to guess system type" >&2 case $UNAME_MACHINE:$UNAME_SYSTEM in mips:Linux | mips64:Linux) # If we got here on MIPS GNU/Linux, output extra information. cat >&2 <&2 <&2 </dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` /bin/uname -X = `(/bin/uname -X) 2>/dev/null` hostinfo = `(hostinfo) 2>/dev/null` /bin/universe = `(/bin/universe) 2>/dev/null` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` /bin/arch = `(/bin/arch) 2>/dev/null` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` UNAME_MACHINE = "$UNAME_MACHINE" UNAME_RELEASE = "$UNAME_RELEASE" UNAME_SYSTEM = "$UNAME_SYSTEM" UNAME_VERSION = "$UNAME_VERSION" EOF fi exit 1 # Local variables: # eval: (add-hook 'before-save-hook 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: librecast/config.sub000066400000000000000000001051161502456746400150270ustar00rootroot00000000000000#! /bin/sh # Configuration validation subroutine script. # Copyright 1992-2022 Free Software Foundation, Inc. # shellcheck disable=SC2006,SC2268 # see below for rationale timestamp='2022-01-03' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 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 . # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that # program. This Exception is an additional permission under section 7 # of the GNU General Public License, version 3 ("GPLv3"). # Please send patches to . # # Configuration subroutine to validate and canonicalize a configuration type. # Supply the specified configuration type as an argument. # If it is invalid, we print an error message on stderr and exit with code 1. # Otherwise, we print the canonical config type on stdout and succeed. # You can get the latest version of this script from: # https://git.savannah.gnu.org/cgit/config.git/plain/config.sub # This file is supposed to be the same for all GNU packages # and recognize all the CPU types, system types and aliases # that are meaningful with *any* GNU software. # Each package is responsible for reporting which valid configurations # it does not support. The user should be able to distinguish # a failure to support a valid configuration from a meaningless # configuration. # The goal of this file is to map all the various variations of a given # machine specification into a single specification in the form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM # or in some cases, the newer four-part form: # CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM # It is wrong to echo any other type of specification. # The "shellcheck disable" line above the timestamp inhibits complaints # about features and limitations of the classic Bourne shell that were # superseded or lifted in POSIX. However, this script identifies a wide # variety of pre-POSIX systems that do not have POSIX shells at all, and # even some reasonably current systems (Solaris 10 as case-in-point) still # have a pre-POSIX /bin/sh. me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] CPU-MFR-OPSYS or ALIAS Canonicalize a configuration name. Options: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.sub ($timestamp) Copyright 1992-2022 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit ;; --version | -v ) echo "$version" ; exit ;; --help | --h* | -h ) echo "$usage"; exit ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" >&2 exit 1 ;; *local*) # First pass through any local machine types. echo "$1" exit ;; * ) break ;; esac done case $# in 0) echo "$me: missing argument$help" >&2 exit 1;; 1) ;; *) echo "$me: too many arguments$help" >&2 exit 1;; esac # Split fields of configuration type # shellcheck disable=SC2162 saved_IFS=$IFS IFS="-" read field1 field2 field3 field4 <&2 exit 1 ;; *-*-*-*) basic_machine=$field1-$field2 basic_os=$field3-$field4 ;; *-*-*) # Ambiguous whether COMPANY is present, or skipped and KERNEL-OS is two # parts maybe_os=$field2-$field3 case $maybe_os in nto-qnx* | linux-* | uclinux-uclibc* \ | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* \ | netbsd*-eabi* | kopensolaris*-gnu* | cloudabi*-eabi* \ | storm-chaos* | os2-emx* | rtmk-nova*) basic_machine=$field1 basic_os=$maybe_os ;; android-linux) basic_machine=$field1-unknown basic_os=linux-android ;; *) basic_machine=$field1-$field2 basic_os=$field3 ;; esac ;; *-*) # A lone config we happen to match not fitting any pattern case $field1-$field2 in decstation-3100) basic_machine=mips-dec basic_os= ;; *-*) # Second component is usually, but not always the OS case $field2 in # Prevent following clause from handling this valid os sun*os*) basic_machine=$field1 basic_os=$field2 ;; zephyr*) basic_machine=$field1-unknown basic_os=$field2 ;; # Manufacturers dec* | mips* | sequent* | encore* | pc533* | sgi* | sony* \ | att* | 7300* | 3300* | delta* | motorola* | sun[234]* \ | unicom* | ibm* | next | hp | isi* | apollo | altos* \ | convergent* | ncr* | news | 32* | 3600* | 3100* \ | hitachi* | c[123]* | convex* | sun | crds | omron* | dg \ | ultra | tti* | harris | dolphin | highlevel | gould \ | cbm | ns | masscomp | apple | axis | knuth | cray \ | microblaze* | sim | cisco \ | oki | wec | wrs | winbond) basic_machine=$field1-$field2 basic_os= ;; *) basic_machine=$field1 basic_os=$field2 ;; esac ;; esac ;; *) # Convert single-component short-hands not valid as part of # multi-component configurations. case $field1 in 386bsd) basic_machine=i386-pc basic_os=bsd ;; a29khif) basic_machine=a29k-amd basic_os=udi ;; adobe68k) basic_machine=m68010-adobe basic_os=scout ;; alliant) basic_machine=fx80-alliant basic_os= ;; altos | altos3068) basic_machine=m68k-altos basic_os= ;; am29k) basic_machine=a29k-none basic_os=bsd ;; amdahl) basic_machine=580-amdahl basic_os=sysv ;; amiga) basic_machine=m68k-unknown basic_os= ;; amigaos | amigados) basic_machine=m68k-unknown basic_os=amigaos ;; amigaunix | amix) basic_machine=m68k-unknown basic_os=sysv4 ;; apollo68) basic_machine=m68k-apollo basic_os=sysv ;; apollo68bsd) basic_machine=m68k-apollo basic_os=bsd ;; aros) basic_machine=i386-pc basic_os=aros ;; aux) basic_machine=m68k-apple basic_os=aux ;; balance) basic_machine=ns32k-sequent basic_os=dynix ;; blackfin) basic_machine=bfin-unknown basic_os=linux ;; cegcc) basic_machine=arm-unknown basic_os=cegcc ;; convex-c1) basic_machine=c1-convex basic_os=bsd ;; convex-c2) basic_machine=c2-convex basic_os=bsd ;; convex-c32) basic_machine=c32-convex basic_os=bsd ;; convex-c34) basic_machine=c34-convex basic_os=bsd ;; convex-c38) basic_machine=c38-convex basic_os=bsd ;; cray) basic_machine=j90-cray basic_os=unicos ;; crds | unos) basic_machine=m68k-crds basic_os= ;; da30) basic_machine=m68k-da30 basic_os= ;; decstation | pmax | pmin | dec3100 | decstatn) basic_machine=mips-dec basic_os= ;; delta88) basic_machine=m88k-motorola basic_os=sysv3 ;; dicos) basic_machine=i686-pc basic_os=dicos ;; djgpp) basic_machine=i586-pc basic_os=msdosdjgpp ;; ebmon29k) basic_machine=a29k-amd basic_os=ebmon ;; es1800 | OSE68k | ose68k | ose | OSE) basic_machine=m68k-ericsson basic_os=ose ;; gmicro) basic_machine=tron-gmicro basic_os=sysv ;; go32) basic_machine=i386-pc basic_os=go32 ;; h8300hms) basic_machine=h8300-hitachi basic_os=hms ;; h8300xray) basic_machine=h8300-hitachi basic_os=xray ;; h8500hms) basic_machine=h8500-hitachi basic_os=hms ;; harris) basic_machine=m88k-harris basic_os=sysv3 ;; hp300 | hp300hpux) basic_machine=m68k-hp basic_os=hpux ;; hp300bsd) basic_machine=m68k-hp basic_os=bsd ;; hppaosf) basic_machine=hppa1.1-hp basic_os=osf ;; hppro) basic_machine=hppa1.1-hp basic_os=proelf ;; i386mach) basic_machine=i386-mach basic_os=mach ;; isi68 | isi) basic_machine=m68k-isi basic_os=sysv ;; m68knommu) basic_machine=m68k-unknown basic_os=linux ;; magnum | m3230) basic_machine=mips-mips basic_os=sysv ;; merlin) basic_machine=ns32k-utek basic_os=sysv ;; mingw64) basic_machine=x86_64-pc basic_os=mingw64 ;; mingw32) basic_machine=i686-pc basic_os=mingw32 ;; mingw32ce) basic_machine=arm-unknown basic_os=mingw32ce ;; monitor) basic_machine=m68k-rom68k basic_os=coff ;; morphos) basic_machine=powerpc-unknown basic_os=morphos ;; moxiebox) basic_machine=moxie-unknown basic_os=moxiebox ;; msdos) basic_machine=i386-pc basic_os=msdos ;; msys) basic_machine=i686-pc basic_os=msys ;; mvs) basic_machine=i370-ibm basic_os=mvs ;; nacl) basic_machine=le32-unknown basic_os=nacl ;; ncr3000) basic_machine=i486-ncr basic_os=sysv4 ;; netbsd386) basic_machine=i386-pc basic_os=netbsd ;; netwinder) basic_machine=armv4l-rebel basic_os=linux ;; news | news700 | news800 | news900) basic_machine=m68k-sony basic_os=newsos ;; news1000) basic_machine=m68030-sony basic_os=newsos ;; necv70) basic_machine=v70-nec basic_os=sysv ;; nh3000) basic_machine=m68k-harris basic_os=cxux ;; nh[45]000) basic_machine=m88k-harris basic_os=cxux ;; nindy960) basic_machine=i960-intel basic_os=nindy ;; mon960) basic_machine=i960-intel basic_os=mon960 ;; nonstopux) basic_machine=mips-compaq basic_os=nonstopux ;; os400) basic_machine=powerpc-ibm basic_os=os400 ;; OSE68000 | ose68000) basic_machine=m68000-ericsson basic_os=ose ;; os68k) basic_machine=m68k-none basic_os=os68k ;; paragon) basic_machine=i860-intel basic_os=osf ;; parisc) basic_machine=hppa-unknown basic_os=linux ;; psp) basic_machine=mipsallegrexel-sony basic_os=psp ;; pw32) basic_machine=i586-unknown basic_os=pw32 ;; rdos | rdos64) basic_machine=x86_64-pc basic_os=rdos ;; rdos32) basic_machine=i386-pc basic_os=rdos ;; rom68k) basic_machine=m68k-rom68k basic_os=coff ;; sa29200) basic_machine=a29k-amd basic_os=udi ;; sei) basic_machine=mips-sei basic_os=seiux ;; sequent) basic_machine=i386-sequent basic_os= ;; sps7) basic_machine=m68k-bull basic_os=sysv2 ;; st2000) basic_machine=m68k-tandem basic_os= ;; stratus) basic_machine=i860-stratus basic_os=sysv4 ;; sun2) basic_machine=m68000-sun basic_os= ;; sun2os3) basic_machine=m68000-sun basic_os=sunos3 ;; sun2os4) basic_machine=m68000-sun basic_os=sunos4 ;; sun3) basic_machine=m68k-sun basic_os= ;; sun3os3) basic_machine=m68k-sun basic_os=sunos3 ;; sun3os4) basic_machine=m68k-sun basic_os=sunos4 ;; sun4) basic_machine=sparc-sun basic_os= ;; sun4os3) basic_machine=sparc-sun basic_os=sunos3 ;; sun4os4) basic_machine=sparc-sun basic_os=sunos4 ;; sun4sol2) basic_machine=sparc-sun basic_os=solaris2 ;; sun386 | sun386i | roadrunner) basic_machine=i386-sun basic_os= ;; sv1) basic_machine=sv1-cray basic_os=unicos ;; symmetry) basic_machine=i386-sequent basic_os=dynix ;; t3e) basic_machine=alphaev5-cray basic_os=unicos ;; t90) basic_machine=t90-cray basic_os=unicos ;; toad1) basic_machine=pdp10-xkl basic_os=tops20 ;; tpf) basic_machine=s390x-ibm basic_os=tpf ;; udi29k) basic_machine=a29k-amd basic_os=udi ;; ultra3) basic_machine=a29k-nyu basic_os=sym1 ;; v810 | necv810) basic_machine=v810-nec basic_os=none ;; vaxv) basic_machine=vax-dec basic_os=sysv ;; vms) basic_machine=vax-dec basic_os=vms ;; vsta) basic_machine=i386-pc basic_os=vsta ;; vxworks960) basic_machine=i960-wrs basic_os=vxworks ;; vxworks68) basic_machine=m68k-wrs basic_os=vxworks ;; vxworks29k) basic_machine=a29k-wrs basic_os=vxworks ;; xbox) basic_machine=i686-pc basic_os=mingw32 ;; ymp) basic_machine=ymp-cray basic_os=unicos ;; *) basic_machine=$1 basic_os= ;; esac ;; esac # Decode 1-component or ad-hoc basic machines case $basic_machine in # Here we handle the default manufacturer of certain CPU types. It is in # some cases the only manufacturer, in others, it is the most popular. w89k) cpu=hppa1.1 vendor=winbond ;; op50n) cpu=hppa1.1 vendor=oki ;; op60c) cpu=hppa1.1 vendor=oki ;; ibm*) cpu=i370 vendor=ibm ;; orion105) cpu=clipper vendor=highlevel ;; mac | mpw | mac-mpw) cpu=m68k vendor=apple ;; pmac | pmac-mpw) cpu=powerpc vendor=apple ;; # Recognize the various machine names and aliases which stand # for a CPU type and a company and sometimes even an OS. 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) cpu=m68000 vendor=att ;; 3b*) cpu=we32k vendor=att ;; bluegene*) cpu=powerpc vendor=ibm basic_os=cnk ;; decsystem10* | dec10*) cpu=pdp10 vendor=dec basic_os=tops10 ;; decsystem20* | dec20*) cpu=pdp10 vendor=dec basic_os=tops20 ;; delta | 3300 | motorola-3300 | motorola-delta \ | 3300-motorola | delta-motorola) cpu=m68k vendor=motorola ;; dpx2*) cpu=m68k vendor=bull basic_os=sysv3 ;; encore | umax | mmax) cpu=ns32k vendor=encore ;; elxsi) cpu=elxsi vendor=elxsi basic_os=${basic_os:-bsd} ;; fx2800) cpu=i860 vendor=alliant ;; genix) cpu=ns32k vendor=ns ;; h3050r* | hiux*) cpu=hppa1.1 vendor=hitachi basic_os=hiuxwe2 ;; hp3k9[0-9][0-9] | hp9[0-9][0-9]) cpu=hppa1.0 vendor=hp ;; hp9k2[0-9][0-9] | hp9k31[0-9]) cpu=m68000 vendor=hp ;; hp9k3[2-9][0-9]) cpu=m68k vendor=hp ;; hp9k6[0-9][0-9] | hp6[0-9][0-9]) cpu=hppa1.0 vendor=hp ;; hp9k7[0-79][0-9] | hp7[0-79][0-9]) cpu=hppa1.1 vendor=hp ;; hp9k78[0-9] | hp78[0-9]) # FIXME: really hppa2.0-hp cpu=hppa1.1 vendor=hp ;; hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) # FIXME: really hppa2.0-hp cpu=hppa1.1 vendor=hp ;; hp9k8[0-9][13679] | hp8[0-9][13679]) cpu=hppa1.1 vendor=hp ;; hp9k8[0-9][0-9] | hp8[0-9][0-9]) cpu=hppa1.0 vendor=hp ;; i*86v32) cpu=`echo "$1" | sed -e 's/86.*/86/'` vendor=pc basic_os=sysv32 ;; i*86v4*) cpu=`echo "$1" | sed -e 's/86.*/86/'` vendor=pc basic_os=sysv4 ;; i*86v) cpu=`echo "$1" | sed -e 's/86.*/86/'` vendor=pc basic_os=sysv ;; i*86sol2) cpu=`echo "$1" | sed -e 's/86.*/86/'` vendor=pc basic_os=solaris2 ;; j90 | j90-cray) cpu=j90 vendor=cray basic_os=${basic_os:-unicos} ;; iris | iris4d) cpu=mips vendor=sgi case $basic_os in irix*) ;; *) basic_os=irix4 ;; esac ;; miniframe) cpu=m68000 vendor=convergent ;; *mint | mint[0-9]* | *MiNT | *MiNT[0-9]*) cpu=m68k vendor=atari basic_os=mint ;; news-3600 | risc-news) cpu=mips vendor=sony basic_os=newsos ;; next | m*-next) cpu=m68k vendor=next case $basic_os in openstep*) ;; nextstep*) ;; ns2*) basic_os=nextstep2 ;; *) basic_os=nextstep3 ;; esac ;; np1) cpu=np1 vendor=gould ;; op50n-* | op60c-*) cpu=hppa1.1 vendor=oki basic_os=proelf ;; pa-hitachi) cpu=hppa1.1 vendor=hitachi basic_os=hiuxwe2 ;; pbd) cpu=sparc vendor=tti ;; pbb) cpu=m68k vendor=tti ;; pc532) cpu=ns32k vendor=pc532 ;; pn) cpu=pn vendor=gould ;; power) cpu=power vendor=ibm ;; ps2) cpu=i386 vendor=ibm ;; rm[46]00) cpu=mips vendor=siemens ;; rtpc | rtpc-*) cpu=romp vendor=ibm ;; sde) cpu=mipsisa32 vendor=sde basic_os=${basic_os:-elf} ;; simso-wrs) cpu=sparclite vendor=wrs basic_os=vxworks ;; tower | tower-32) cpu=m68k vendor=ncr ;; vpp*|vx|vx-*) cpu=f301 vendor=fujitsu ;; w65) cpu=w65 vendor=wdc ;; w89k-*) cpu=hppa1.1 vendor=winbond basic_os=proelf ;; none) cpu=none vendor=none ;; leon|leon[3-9]) cpu=sparc vendor=$basic_machine ;; leon-*|leon[3-9]-*) cpu=sparc vendor=`echo "$basic_machine" | sed 's/-.*//'` ;; *-*) # shellcheck disable=SC2162 saved_IFS=$IFS IFS="-" read cpu vendor <&2 exit 1 ;; esac ;; esac # Here we canonicalize certain aliases for manufacturers. case $vendor in digital*) vendor=dec ;; commodore*) vendor=cbm ;; *) ;; esac # Decode manufacturer-specific aliases for certain operating systems. if test x$basic_os != x then # First recognize some ad-hoc cases, or perhaps split kernel-os, or else just # set os. case $basic_os in gnu/linux*) kernel=linux os=`echo "$basic_os" | sed -e 's|gnu/linux|gnu|'` ;; os2-emx) kernel=os2 os=`echo "$basic_os" | sed -e 's|os2-emx|emx|'` ;; nto-qnx*) kernel=nto os=`echo "$basic_os" | sed -e 's|nto-qnx|qnx|'` ;; *-*) # shellcheck disable=SC2162 saved_IFS=$IFS IFS="-" read kernel os <&2 exit 1 ;; esac # As a final step for OS-related things, validate the OS-kernel combination # (given a valid OS), if there is a kernel. case $kernel-$os in linux-gnu* | linux-dietlibc* | linux-android* | linux-newlib* \ | linux-musl* | linux-relibc* | linux-uclibc* ) ;; uclinux-uclibc* ) ;; -dietlibc* | -newlib* | -musl* | -relibc* | -uclibc* ) # These are just libc implementations, not actual OSes, and thus # require a kernel. echo "Invalid configuration \`$1': libc \`$os' needs explicit kernel." 1>&2 exit 1 ;; kfreebsd*-gnu* | kopensolaris*-gnu*) ;; vxworks-simlinux | vxworks-simwindows | vxworks-spe) ;; nto-qnx*) ;; os2-emx) ;; *-eabi* | *-gnueabi*) ;; -*) # Blank kernel with real OS is always fine. ;; *-*) echo "Invalid configuration \`$1': Kernel \`$kernel' not known to work with OS \`$os'." 1>&2 exit 1 ;; esac # Here we handle the case where we know the os, and the CPU type, but not the # manufacturer. We pick the logical manufacturer. case $vendor in unknown) case $cpu-$os in *-riscix*) vendor=acorn ;; *-sunos*) vendor=sun ;; *-cnk* | *-aix*) vendor=ibm ;; *-beos*) vendor=be ;; *-hpux*) vendor=hp ;; *-mpeix*) vendor=hp ;; *-hiux*) vendor=hitachi ;; *-unos*) vendor=crds ;; *-dgux*) vendor=dg ;; *-luna*) vendor=omron ;; *-genix*) vendor=ns ;; *-clix*) vendor=intergraph ;; *-mvs* | *-opened*) vendor=ibm ;; *-os400*) vendor=ibm ;; s390-* | s390x-*) vendor=ibm ;; *-ptx*) vendor=sequent ;; *-tpf*) vendor=ibm ;; *-vxsim* | *-vxworks* | *-windiss*) vendor=wrs ;; *-aux*) vendor=apple ;; *-hms*) vendor=hitachi ;; *-mpw* | *-macos*) vendor=apple ;; *-*mint | *-mint[0-9]* | *-*MiNT | *-MiNT[0-9]*) vendor=atari ;; *-vos*) vendor=stratus ;; esac ;; esac echo "$cpu-$vendor-${kernel:+$kernel-}$os" exit # Local variables: # eval: (add-hook 'before-save-hook 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: librecast/configure000077500000000000000000006303111502456746400147560ustar00rootroot00000000000000#! /bin/sh # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.71 for librecast 0.11.2. # # Report bugs to . # # # Copyright (C) 1992-1996, 1998-2017, 2020-2021 Free Software Foundation, # Inc. # # # This configure script is free software; the Free Software Foundation # gives unlimited permission to copy, distribute and modify it. # # Copyright (c) 2016-2025 Brett Sheffield # See COPYING for license details. # ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh as_nop=: if test ${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else $as_nop case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi # Reset variables that may have inherited troublesome values from # the environment. # IFS needs to be set, to space, tab, and newline, in precisely that order. # (If _AS_PATH_WALK were called with IFS unset, it would have the # side effect of setting IFS to empty, thus disabling word splitting.) # Quoting is to prevent editors from complaining about space-tab. as_nl=' ' export as_nl IFS=" "" $as_nl" PS1='$ ' PS2='> ' PS4='+ ' # Ensure predictable behavior from utilities with locale-dependent output. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # We cannot yet rely on "unset" to work, but we need these variables # to be unset--not just set to an empty or harmless value--now, to # avoid bugs in old shells (e.g. pre-3.0 UWIN ksh). This construct # also avoids known problems related to "unset" and subshell syntax # in other old shells (e.g. bash 2.01 and pdksh 5.2.14). for as_var in BASH_ENV ENV MAIL MAILPATH CDPATH do eval test \${$as_var+y} \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done # Ensure that fds 0, 1, and 2 are open. if (exec 3>&0) 2>/dev/null; then :; else exec 0&1) 2>/dev/null; then :; else exec 1>/dev/null; fi if (exec 3>&2) ; then :; else exec 2>/dev/null; fi # The user is always right. if ${PATH_SEPARATOR+false} :; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac test -r "$as_dir$0" && as_myself=$as_dir$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then printf "%s\n" "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Use a proper internal environment variable to ensure we don't fall # into an infinite loop, continuously re-executing ourselves. if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then _as_can_reexec=no; export _as_can_reexec; # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV case $- in # (((( *v*x* | *x*v* ) as_opts=-vx ;; *v* ) as_opts=-v ;; *x* ) as_opts=-x ;; * ) as_opts= ;; esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. printf "%s\n" "$0: could not re-execute with $CONFIG_SHELL" >&2 exit 255 fi # We don't want this to propagate to other subprocesses. { _as_can_reexec=; unset _as_can_reexec;} if test "x$CONFIG_SHELL" = x; then as_bourne_compatible="as_nop=: if test \${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which # is contrary to our usage. Disable this feature. alias -g '\${1+\"\$@\"}'='\"\$@\"' setopt NO_GLOB_SUBST else \$as_nop case \`(set -o) 2>/dev/null\` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi " as_required="as_fn_return () { (exit \$1); } as_fn_success () { as_fn_return 0; } as_fn_failure () { as_fn_return 1; } as_fn_ret_success () { return 0; } as_fn_ret_failure () { return 1; } exitcode=0 as_fn_success || { exitcode=1; echo as_fn_success failed.; } as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } if ( set x; as_fn_ret_success y && test x = \"\$1\" ) then : else \$as_nop exitcode=1; echo positional parameters were not saved. fi test x\$exitcode = x0 || exit 1 blah=\$(echo \$(echo blah)) test x\"\$blah\" = xblah || exit 1 test -x / || exit 1" as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 test \$(( 1 + 1 )) = 2 || exit 1" if (eval "$as_required") 2>/dev/null then : as_have_required=yes else $as_nop as_have_required=no fi if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null then : else $as_nop as_save_IFS=$IFS; IFS=$PATH_SEPARATOR as_found=false for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac as_found=: case $as_dir in #( /*) for as_base in sh bash ksh sh5; do # Try only shells that exist, to save several forks. as_shell=$as_dir$as_base if { test -f "$as_shell" || test -f "$as_shell.exe"; } && as_run=a "$as_shell" -c "$as_bourne_compatible""$as_required" 2>/dev/null then : CONFIG_SHELL=$as_shell as_have_required=yes if as_run=a "$as_shell" -c "$as_bourne_compatible""$as_suggested" 2>/dev/null then : break 2 fi fi done;; esac as_found=false done IFS=$as_save_IFS if $as_found then : else $as_nop if { test -f "$SHELL" || test -f "$SHELL.exe"; } && as_run=a "$SHELL" -c "$as_bourne_compatible""$as_required" 2>/dev/null then : CONFIG_SHELL=$SHELL as_have_required=yes fi fi if test "x$CONFIG_SHELL" != x then : export CONFIG_SHELL # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV case $- in # (((( *v*x* | *x*v* ) as_opts=-vx ;; *v* ) as_opts=-v ;; *x* ) as_opts=-x ;; * ) as_opts= ;; esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. printf "%s\n" "$0: could not re-execute with $CONFIG_SHELL" >&2 exit 255 fi if test x$as_have_required = xno then : printf "%s\n" "$0: This script requires a shell more modern than all" printf "%s\n" "$0: the shells that I found on your system." if test ${ZSH_VERSION+y} ; then printf "%s\n" "$0: In particular, zsh $ZSH_VERSION has bugs and should" printf "%s\n" "$0: be upgraded to zsh 4.3.4 or later." else printf "%s\n" "$0: Please tell bug-autoconf@gnu.org and bugs@librecast.net $0: about your system, including any error possibly output $0: before this message. Then install a modern shell, or $0: manually run the script under such a shell if you do $0: have one." fi exit 1 fi fi fi SHELL=${CONFIG_SHELL-/bin/sh} export SHELL # Unset more variables known to interfere with behavior of common tools. CLICOLOR_FORCE= GREP_OPTIONS= unset CLICOLOR_FORCE GREP_OPTIONS ## --------------------- ## ## M4sh Shell Functions. ## ## --------------------- ## # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_nop # --------- # Do nothing but, unlike ":", preserve the value of $?. as_fn_nop () { return $? } as_nop=as_fn_nop # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`printf "%s\n" "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || printf "%s\n" X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p # as_fn_executable_p FILE # ----------------------- # Test if FILE is an executable regular file. as_fn_executable_p () { test -f "$1" && test -x "$1" } # as_fn_executable_p # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null then : eval 'as_fn_append () { eval $1+=\$2 }' else $as_nop as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null then : eval 'as_fn_arith () { as_val=$(( $* )) }' else $as_nop as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith # as_fn_nop # --------- # Do nothing but, unlike ":", preserve the value of $?. as_fn_nop () { return $? } as_nop=as_fn_nop # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi printf "%s\n" "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || printf "%s\n" X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits as_lineno_1=$LINENO as_lineno_1a=$LINENO as_lineno_2=$LINENO as_lineno_2a=$LINENO eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) sed -n ' p /[$]LINENO/= ' <$as_myself | sed ' s/[$]LINENO.*/&-/ t lineno b :lineno N :loop s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ t loop s/-\n.*// ' >$as_me.lineno && chmod +x "$as_me.lineno" || { printf "%s\n" "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } # If we had to re-execute with $CONFIG_SHELL, we're ensured to have # already done that, so ensure we don't try to do so again and fall # in an infinite loop. This has already happened in practice. _as_can_reexec=no; export _as_can_reexec # Don't try to exec as it changes $[0], causing all sort of problems # (the dirname of $[0] is not the place where we might find the # original and so on. Autoconf is especially sensitive to this). . "./$as_me.lineno" # Exit status is that of the last command. exit } # Determine whether it's possible to make 'echo' print without a newline. # These variables are no longer used directly by Autoconf, but are AC_SUBSTed # for compatibility with existing Makefiles. ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac # For backward compatibility with old third-party macros, we provide # the shell variables $as_echo and $as_echo_n. New code should use # AS_ECHO(["message"]) and AS_ECHO_N(["message"]), respectively. as_echo='printf %s\n' as_echo_n='printf %s' rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -pR' fi else as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi as_test_x='test -x' as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" test -n "$DJDIR" || exec 7<&0 &1 # Name of the host. # hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, # so uname gets run too. ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` # # Initializations. # ac_default_prefix=/usr/local ac_clean_files= ac_config_libobj_dir=. LIBOBJS= cross_compiling=no subdirs= MFLAGS= MAKEFLAGS= # Identity of this package. PACKAGE_NAME='librecast' PACKAGE_TARNAME='librecast' PACKAGE_VERSION='0.11.2' PACKAGE_STRING='librecast 0.11.2' PACKAGE_BUGREPORT='bugs@librecast.net' PACKAGE_URL='' ac_unique_file="src/" # Factoring default headers for most tests. ac_includes_default="\ #include #ifdef HAVE_STDIO_H # include #endif #ifdef HAVE_STDLIB_H # include #endif #ifdef HAVE_STRING_H # include #endif #ifdef HAVE_INTTYPES_H # include #endif #ifdef HAVE_STDINT_H # include #endif #ifdef HAVE_STRINGS_H # include #endif #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_STAT_H # include #endif #ifdef HAVE_UNISTD_H # include #endif" ac_header_c_list= ac_func_c_list= enable_option_checking=no ac_subst_vars='LTLIBOBJS subdirs LIBOBJS host_os host_vendor host_cpu host build_os build_vendor build_cpu build EGREP GREP CPP INCLUDE_LCRQ LIBLCRQ HAVE_LIBLCRQ HASH_STATE HASHSIZE HASH_TYPE INCSODIUM LIBSODIUM HAVE_LIBSODIUM INCMLD MLD_HEADERS OBJMLD LIBMLD MLD INCBLAKE3 LIBBLAKE3 BLAKE3 ROUTE IPROUTE iproute IFCONFIG ifconfig FALSE TESTRUNNER testrunner LN_S INSTALL_DATA INSTALL_SCRIPT INSTALL_PROGRAM OBJEXT EXEEXT ac_ct_CC CPPFLAGS LDFLAGS CFLAGS CC PACKAGE_ABIVERS target_alias host_alias build_alias LIBS ECHO_T ECHO_N ECHO_C DEFS mandir localedir libdir psdir pdfdir dvidir htmldir infodir docdir oldincludedir includedir runstatedir localstatedir sharedstatedir sysconfdir datadir datarootdir libexecdir sbindir bindir program_transform_name prefix exec_prefix PACKAGE_URL PACKAGE_BUGREPORT PACKAGE_STRING PACKAGE_VERSION PACKAGE_TARNAME PACKAGE_NAME PATH_SEPARATOR SHELL' ac_subst_files='' ac_user_opts=' enable_option_checking with_mld with_blake3 with_sodium with_lcrq ' ac_precious_vars='build_alias host_alias target_alias CC CFLAGS LDFLAGS LIBS CPPFLAGS CPP' ac_subdirs_all='libs/libmld' # Initialize some variables set by options. ac_init_help= ac_init_version=false ac_unrecognized_opts= ac_unrecognized_sep= # The variables have the same names as the options, with # dashes changed to underlines. cache_file=/dev/null exec_prefix=NONE no_create= no_recursion= prefix=NONE program_prefix=NONE program_suffix=NONE program_transform_name=s,x,x, silent= site= srcdir= verbose= x_includes=NONE x_libraries=NONE # Installation directory options. # These are left unexpanded so users can "make install exec_prefix=/foo" # and all the variables that are supposed to be based on exec_prefix # by default will actually change. # Use braces instead of parens because sh, perl, etc. also accept them. # (The list follows the same order as the GNU Coding Standards.) bindir='${exec_prefix}/bin' sbindir='${exec_prefix}/sbin' libexecdir='${exec_prefix}/libexec' datarootdir='${prefix}/share' datadir='${datarootdir}' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' runstatedir='${localstatedir}/run' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' infodir='${datarootdir}/info' htmldir='${docdir}' dvidir='${docdir}' pdfdir='${docdir}' psdir='${docdir}' libdir='${exec_prefix}/lib' localedir='${datarootdir}/locale' mandir='${datarootdir}/man' ac_prev= ac_dashdash= for ac_option do # If the previous option needs an argument, assign it. if test -n "$ac_prev"; then eval $ac_prev=\$ac_option ac_prev= continue fi case $ac_option in *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; *=) ac_optarg= ;; *) ac_optarg=yes ;; esac case $ac_dashdash$ac_option in --) ac_dashdash=yes ;; -bindir | --bindir | --bindi | --bind | --bin | --bi) ac_prev=bindir ;; -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) bindir=$ac_optarg ;; -build | --build | --buil | --bui | --bu) ac_prev=build_alias ;; -build=* | --build=* | --buil=* | --bui=* | --bu=*) build_alias=$ac_optarg ;; -cache-file | --cache-file | --cache-fil | --cache-fi \ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) ac_prev=cache_file ;; -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) cache_file=$ac_optarg ;; --config-cache | -C) cache_file=config.cache ;; -datadir | --datadir | --datadi | --datad) ac_prev=datadir ;; -datadir=* | --datadir=* | --datadi=* | --datad=*) datadir=$ac_optarg ;; -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ | --dataroo | --dataro | --datar) ac_prev=datarootdir ;; -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) datarootdir=$ac_optarg ;; -disable-* | --disable-*) ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: \`$ac_useropt'" ac_useropt_orig=$ac_useropt ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=no ;; -docdir | --docdir | --docdi | --doc | --do) ac_prev=docdir ;; -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) docdir=$ac_optarg ;; -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) ac_prev=dvidir ;; -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) dvidir=$ac_optarg ;; -enable-* | --enable-*) ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: \`$ac_useropt'" ac_useropt_orig=$ac_useropt ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=\$ac_optarg ;; -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ | --exec | --exe | --ex) ac_prev=exec_prefix ;; -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ | --exec=* | --exe=* | --ex=*) exec_prefix=$ac_optarg ;; -gas | --gas | --ga | --g) # Obsolete; use --with-gas. with_gas=yes ;; -help | --help | --hel | --he | -h) ac_init_help=long ;; -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) ac_init_help=recursive ;; -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) ac_init_help=short ;; -host | --host | --hos | --ho) ac_prev=host_alias ;; -host=* | --host=* | --hos=* | --ho=*) host_alias=$ac_optarg ;; -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) ac_prev=htmldir ;; -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ | --ht=*) htmldir=$ac_optarg ;; -includedir | --includedir | --includedi | --included | --include \ | --includ | --inclu | --incl | --inc) ac_prev=includedir ;; -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ | --includ=* | --inclu=* | --incl=* | --inc=*) includedir=$ac_optarg ;; -infodir | --infodir | --infodi | --infod | --info | --inf) ac_prev=infodir ;; -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) infodir=$ac_optarg ;; -libdir | --libdir | --libdi | --libd) ac_prev=libdir ;; -libdir=* | --libdir=* | --libdi=* | --libd=*) libdir=$ac_optarg ;; -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ | --libexe | --libex | --libe) ac_prev=libexecdir ;; -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ | --libexe=* | --libex=* | --libe=*) libexecdir=$ac_optarg ;; -localedir | --localedir | --localedi | --localed | --locale) ac_prev=localedir ;; -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) localedir=$ac_optarg ;; -localstatedir | --localstatedir | --localstatedi | --localstated \ | --localstate | --localstat | --localsta | --localst | --locals) ac_prev=localstatedir ;; -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) localstatedir=$ac_optarg ;; -mandir | --mandir | --mandi | --mand | --man | --ma | --m) ac_prev=mandir ;; -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) mandir=$ac_optarg ;; -nfp | --nfp | --nf) # Obsolete; use --without-fp. with_fp=no ;; -no-create | --no-create | --no-creat | --no-crea | --no-cre \ | --no-cr | --no-c | -n) no_create=yes ;; -no-recursion | --no-recursion | --no-recursio | --no-recursi \ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) no_recursion=yes ;; -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ | --oldin | --oldi | --old | --ol | --o) ac_prev=oldincludedir ;; -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) oldincludedir=$ac_optarg ;; -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) ac_prev=prefix ;; -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) prefix=$ac_optarg ;; -program-prefix | --program-prefix | --program-prefi | --program-pref \ | --program-pre | --program-pr | --program-p) ac_prev=program_prefix ;; -program-prefix=* | --program-prefix=* | --program-prefi=* \ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) program_prefix=$ac_optarg ;; -program-suffix | --program-suffix | --program-suffi | --program-suff \ | --program-suf | --program-su | --program-s) ac_prev=program_suffix ;; -program-suffix=* | --program-suffix=* | --program-suffi=* \ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) program_suffix=$ac_optarg ;; -program-transform-name | --program-transform-name \ | --program-transform-nam | --program-transform-na \ | --program-transform-n | --program-transform- \ | --program-transform | --program-transfor \ | --program-transfo | --program-transf \ | --program-trans | --program-tran \ | --progr-tra | --program-tr | --program-t) ac_prev=program_transform_name ;; -program-transform-name=* | --program-transform-name=* \ | --program-transform-nam=* | --program-transform-na=* \ | --program-transform-n=* | --program-transform-=* \ | --program-transform=* | --program-transfor=* \ | --program-transfo=* | --program-transf=* \ | --program-trans=* | --program-tran=* \ | --progr-tra=* | --program-tr=* | --program-t=*) program_transform_name=$ac_optarg ;; -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) ac_prev=pdfdir ;; -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) pdfdir=$ac_optarg ;; -psdir | --psdir | --psdi | --psd | --ps) ac_prev=psdir ;; -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) psdir=$ac_optarg ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) silent=yes ;; -runstatedir | --runstatedir | --runstatedi | --runstated \ | --runstate | --runstat | --runsta | --runst | --runs \ | --run | --ru | --r) ac_prev=runstatedir ;; -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \ | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \ | --run=* | --ru=* | --r=*) runstatedir=$ac_optarg ;; -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ | --sbi=* | --sb=*) sbindir=$ac_optarg ;; -sharedstatedir | --sharedstatedir | --sharedstatedi \ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ | --sharedst | --shareds | --shared | --share | --shar \ | --sha | --sh) ac_prev=sharedstatedir ;; -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ | --sha=* | --sh=*) sharedstatedir=$ac_optarg ;; -site | --site | --sit) ac_prev=site ;; -site=* | --site=* | --sit=*) site=$ac_optarg ;; -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) ac_prev=srcdir ;; -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) srcdir=$ac_optarg ;; -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ | --syscon | --sysco | --sysc | --sys | --sy) ac_prev=sysconfdir ;; -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) sysconfdir=$ac_optarg ;; -target | --target | --targe | --targ | --tar | --ta | --t) ac_prev=target_alias ;; -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) target_alias=$ac_optarg ;; -v | -verbose | --verbose | --verbos | --verbo | --verb) verbose=yes ;; -version | --version | --versio | --versi | --vers | -V) ac_init_version=: ;; -with-* | --with-*) ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: \`$ac_useropt'" ac_useropt_orig=$ac_useropt ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=\$ac_optarg ;; -without-* | --without-*) ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: \`$ac_useropt'" ac_useropt_orig=$ac_useropt ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=no ;; --x) # Obsolete; use --with-x. with_x=yes ;; -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ | --x-incl | --x-inc | --x-in | --x-i) ac_prev=x_includes ;; -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) x_includes=$ac_optarg ;; -x-libraries | --x-libraries | --x-librarie | --x-librari \ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) ac_prev=x_libraries ;; -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) x_libraries=$ac_optarg ;; -*) as_fn_error $? "unrecognized option: \`$ac_option' Try \`$0 --help' for more information" ;; *=*) ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` # Reject names that are not valid shell variable names. case $ac_envvar in #( '' | [0-9]* | *[!_$as_cr_alnum]* ) as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; esac eval $ac_envvar=\$ac_optarg export $ac_envvar ;; *) # FIXME: should be removed in autoconf 3.0. printf "%s\n" "$as_me: WARNING: you should use --build, --host, --target" >&2 expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && printf "%s\n" "$as_me: WARNING: invalid host type: $ac_option" >&2 : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" ;; esac done if test -n "$ac_prev"; then ac_option=--`echo $ac_prev | sed 's/_/-/g'` as_fn_error $? "missing argument to $ac_option" fi if test -n "$ac_unrecognized_opts"; then case $enable_option_checking in no) ;; fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; *) printf "%s\n" "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; esac fi # Check all directory arguments for consistency. for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ libdir localedir mandir runstatedir do eval ac_val=\$$ac_var # Remove trailing slashes. case $ac_val in */ ) ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` eval $ac_var=\$ac_val;; esac # Be sure to have absolute directory names. case $ac_val in [\\/$]* | ?:[\\/]* ) continue;; NONE | '' ) case $ac_var in *prefix ) continue;; esac;; esac as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" done # There might be people who depend on the old broken behavior: `$host' # used to hold the argument of --host etc. # FIXME: To remove some day. build=$build_alias host=$host_alias target=$target_alias # FIXME: To remove some day. if test "x$host_alias" != x; then if test "x$build_alias" = x; then cross_compiling=maybe elif test "x$build_alias" != "x$host_alias"; then cross_compiling=yes fi fi ac_tool_prefix= test -n "$host_alias" && ac_tool_prefix=$host_alias- test "$silent" = yes && exec 6>/dev/null ac_pwd=`pwd` && test -n "$ac_pwd" && ac_ls_di=`ls -di .` && ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || as_fn_error $? "working directory cannot be determined" test "X$ac_ls_di" = "X$ac_pwd_ls_di" || as_fn_error $? "pwd does not report name of working directory" # Find the source files, if location was not specified. if test -z "$srcdir"; then ac_srcdir_defaulted=yes # Try the directory containing this script, then the parent directory. ac_confdir=`$as_dirname -- "$as_myself" || $as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_myself" : 'X\(//\)[^/]' \| \ X"$as_myself" : 'X\(//\)$' \| \ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || printf "%s\n" X"$as_myself" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` srcdir=$ac_confdir if test ! -r "$srcdir/$ac_unique_file"; then srcdir=.. fi else ac_srcdir_defaulted=no fi if test ! -r "$srcdir/$ac_unique_file"; then test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" fi ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" ac_abs_confdir=`( cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" pwd)` # When building in place, set srcdir=. if test "$ac_abs_confdir" = "$ac_pwd"; then srcdir=. fi # Remove unnecessary trailing slashes from srcdir. # Double slashes in file names in object file debugging info # mess up M-x gdb in Emacs. case $srcdir in */) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; esac for ac_var in $ac_precious_vars; do eval ac_env_${ac_var}_set=\${${ac_var}+set} eval ac_env_${ac_var}_value=\$${ac_var} eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} eval ac_cv_env_${ac_var}_value=\$${ac_var} done # # Report the --help message. # if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF \`configure' configures librecast 0.11.2 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... To assign environment variables (e.g., CC, CFLAGS...), specify them as VAR=VALUE. See below for descriptions of some of the useful variables. Defaults for the options are specified in brackets. Configuration: -h, --help display this help and exit --help=short display options specific to this package --help=recursive display the short help of all the included packages -V, --version display version information and exit -q, --quiet, --silent do not print \`checking ...' messages --cache-file=FILE cache test results in FILE [disabled] -C, --config-cache alias for \`--cache-file=config.cache' -n, --no-create do not create output files --srcdir=DIR find the sources in DIR [configure dir or \`..'] Installation directories: --prefix=PREFIX install architecture-independent files in PREFIX [$ac_default_prefix] --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX [PREFIX] By default, \`make install' will install all the files in \`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify an installation prefix other than \`$ac_default_prefix' using \`--prefix', for instance \`--prefix=\$HOME'. For better control, use the options below. Fine tuning of the installation directories: --bindir=DIR user executables [EPREFIX/bin] --sbindir=DIR system admin executables [EPREFIX/sbin] --libexecdir=DIR program executables [EPREFIX/libexec] --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] --datadir=DIR read-only architecture-independent data [DATAROOTDIR] --infodir=DIR info documentation [DATAROOTDIR/info] --localedir=DIR locale-dependent data [DATAROOTDIR/locale] --mandir=DIR man documentation [DATAROOTDIR/man] --docdir=DIR documentation root [DATAROOTDIR/doc/librecast] --htmldir=DIR html documentation [DOCDIR] --dvidir=DIR dvi documentation [DOCDIR] --pdfdir=DIR pdf documentation [DOCDIR] --psdir=DIR ps documentation [DOCDIR] _ACEOF cat <<\_ACEOF System types: --build=BUILD configure for building on BUILD [guessed] --host=HOST cross-compile to build programs to run on HOST [BUILD] _ACEOF fi if test -n "$ac_init_help"; then case $ac_init_help in short | recursive ) echo "Configuration of librecast 0.11.2:";; esac cat <<\_ACEOF Optional Packages: --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) --without-mld disable mld --with-blake3 use BLAKE3 for hashing (default is yes) --with-sodium use libsodium for encryption and hashing (default is yes, if available) --with-lcrq use liblcrq for FEC (default is yes, if available) Some influential environment variables: CC C compiler command CFLAGS C compiler flags LDFLAGS linker flags, e.g. -L if you have libraries in a nonstandard directory LIBS libraries to pass to the linker, e.g. -l CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if you have headers in a nonstandard directory CPP C preprocessor Use these variables to override the choices made by `configure' or to help it to find libraries and programs with nonstandard names/locations. Report bugs to . _ACEOF ac_status=$? fi if test "$ac_init_help" = "recursive"; then # If there are subdirs, report their specific --help. for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue test -d "$ac_dir" || { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || continue ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`printf "%s\n" "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`printf "%s\n" "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix cd "$ac_dir" || { ac_status=$?; continue; } # Check for configure.gnu first; this name is used for a wrapper for # Metaconfig's "Configure" on case-insensitive file systems. if test -f "$ac_srcdir/configure.gnu"; then echo && $SHELL "$ac_srcdir/configure.gnu" --help=recursive elif test -f "$ac_srcdir/configure"; then echo && $SHELL "$ac_srcdir/configure" --help=recursive else printf "%s\n" "$as_me: WARNING: no configuration information is in $ac_dir" >&2 fi || ac_status=$? cd "$ac_pwd" || { ac_status=$?; break; } done fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF librecast configure 0.11.2 generated by GNU Autoconf 2.71 Copyright (C) 2021 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. Copyright (c) 2016-2025 Brett Sheffield See COPYING for license details. _ACEOF exit fi ## ------------------------ ## ## Autoconf initialization. ## ## ------------------------ ## # ac_fn_c_try_compile LINENO # -------------------------- # Try to compile conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext conftest.beam if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext then : ac_retval=0 else $as_nop printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_compile # ac_fn_c_try_link LINENO # ----------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_link () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext conftest.beam conftest$ac_exeext if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_link") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || test -x conftest$ac_exeext } then : ac_retval=0 else $as_nop printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would # interfere with the next link command; also delete a directory that is # left behind by Apple's compiler. We do this before executing the actions. rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_link # ac_fn_c_check_func LINENO FUNC VAR # ---------------------------------- # Tests whether FUNC exists, setting the cache variable VAR accordingly ac_fn_c_check_func () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 printf %s "checking for $2... " >&6; } if eval test \${$3+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Define $2 to an innocuous variant, in case declares $2. For example, HP-UX 11i declares gettimeofday. */ #define $2 innocuous_$2 /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $2 (void); below. */ #include #undef $2 /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char $2 (void); /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined __stub_$2 || defined __stub___$2 choke me #endif int main (void) { return $2 (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : eval "$3=yes" else $as_nop eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext fi eval ac_res=\$$3 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 printf "%s\n" "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_func # ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES # ------------------------------------------------------- # Tests whether HEADER exists and can be compiled using the include files in # INCLUDES, setting the cache variable VAR accordingly. ac_fn_c_check_header_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 printf %s "checking for $2... " >&6; } if eval test \${$3+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> _ACEOF if ac_fn_c_try_compile "$LINENO" then : eval "$3=yes" else $as_nop eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi eval ac_res=\$$3 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 printf "%s\n" "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_header_compile # ac_fn_c_check_type LINENO TYPE VAR INCLUDES # ------------------------------------------- # Tests whether TYPE exists after having included INCLUDES, setting cache # variable VAR accordingly. ac_fn_c_check_type () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 printf %s "checking for $2... " >&6; } if eval test \${$3+y} then : printf %s "(cached) " >&6 else $as_nop eval "$3=no" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main (void) { if (sizeof ($2)) return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main (void) { if (sizeof (($2))) return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : else $as_nop eval "$3=yes" fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi eval ac_res=\$$3 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 printf "%s\n" "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_type # ac_fn_c_find_intX_t LINENO BITS VAR # ----------------------------------- # Finds a signed integer type with width BITS, setting cache variable VAR # accordingly. ac_fn_c_find_intX_t () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for int$2_t" >&5 printf %s "checking for int$2_t... " >&6; } if eval test \${$3+y} then : printf %s "(cached) " >&6 else $as_nop eval "$3=no" # Order is important - never check a type that is potentially smaller # than half of the expected target width. for ac_type in int$2_t 'int' 'long int' \ 'long long int' 'short int' 'signed char'; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default enum { N = $2 / 2 - 1 }; int main (void) { static int test_array [1 - 2 * !(0 < ($ac_type) ((((($ac_type) 1 << N) << N) - 1) * 2 + 1))]; test_array [0] = 0; return test_array [0]; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default enum { N = $2 / 2 - 1 }; int main (void) { static int test_array [1 - 2 * !(($ac_type) ((((($ac_type) 1 << N) << N) - 1) * 2 + 1) < ($ac_type) ((((($ac_type) 1 << N) << N) - 1) * 2 + 2))]; test_array [0] = 0; return test_array [0]; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : else $as_nop case $ac_type in #( int$2_t) : eval "$3=yes" ;; #( *) : eval "$3=\$ac_type" ;; esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext if eval test \"x\$"$3"\" = x"no" then : else $as_nop break fi done fi eval ac_res=\$$3 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 printf "%s\n" "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_find_intX_t # ac_fn_c_try_cpp LINENO # ---------------------- # Try to preprocess conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_cpp () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_cpp conftest.$ac_ext" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } > conftest.i && { test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || test ! -s conftest.err } then : ac_retval=0 else $as_nop printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_cpp # ac_fn_c_find_uintX_t LINENO BITS VAR # ------------------------------------ # Finds an unsigned integer type with width BITS, setting cache variable VAR # accordingly. ac_fn_c_find_uintX_t () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for uint$2_t" >&5 printf %s "checking for uint$2_t... " >&6; } if eval test \${$3+y} then : printf %s "(cached) " >&6 else $as_nop eval "$3=no" # Order is important - never check a type that is potentially smaller # than half of the expected target width. for ac_type in uint$2_t 'unsigned int' 'unsigned long int' \ 'unsigned long long int' 'unsigned short int' 'unsigned char'; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default int main (void) { static int test_array [1 - 2 * !((($ac_type) -1 >> ($2 / 2 - 1)) >> ($2 / 2 - 1) == 3)]; test_array [0] = 0; return test_array [0]; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : case $ac_type in #( uint$2_t) : eval "$3=yes" ;; #( *) : eval "$3=\$ac_type" ;; esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext if eval test \"x\$"$3"\" = x"no" then : else $as_nop break fi done fi eval ac_res=\$$3 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 printf "%s\n" "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_find_uintX_t # ac_fn_c_try_run LINENO # ---------------------- # Try to run conftest.$ac_ext, and return whether this succeeded. Assumes that # executables *can* be run. ac_fn_c_try_run () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; } then : ac_retval=0 else $as_nop printf "%s\n" "$as_me: program exited with status $ac_status" >&5 printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=$ac_status fi rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_run ac_configure_args_raw= for ac_arg do case $ac_arg in *\'*) ac_arg=`printf "%s\n" "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac as_fn_append ac_configure_args_raw " '$ac_arg'" done case $ac_configure_args_raw in *$as_nl*) ac_safe_unquote= ;; *) ac_unsafe_z='|&;<>()$`\\"*?[ '' ' # This string ends in space, tab. ac_unsafe_a="$ac_unsafe_z#~" ac_safe_unquote="s/ '\\([^$ac_unsafe_a][^$ac_unsafe_z]*\\)'/ \\1/g" ac_configure_args_raw=` printf "%s\n" "$ac_configure_args_raw" | sed "$ac_safe_unquote"`;; esac cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. It was created by librecast $as_me 0.11.2, which was generated by GNU Autoconf 2.71. Invocation command line was $ $0$ac_configure_args_raw _ACEOF exec 5>>config.log { cat <<_ASUNAME ## --------- ## ## Platform. ## ## --------- ## hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` /bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` /bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` /usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` /bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` /bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` _ASUNAME as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac printf "%s\n" "PATH: $as_dir" done IFS=$as_save_IFS } >&5 cat >&5 <<_ACEOF ## ----------- ## ## Core tests. ## ## ----------- ## _ACEOF # Keep a trace of the command line. # Strip out --no-create and --no-recursion so they do not pile up. # Strip out --silent because we don't want to record it for future runs. # Also quote any args containing shell meta-characters. # Make two passes to allow for proper duplicate-argument suppression. ac_configure_args= ac_configure_args0= ac_configure_args1= ac_must_keep_next=false for ac_pass in 1 2 do for ac_arg do case $ac_arg in -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) continue ;; *\'*) ac_arg=`printf "%s\n" "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac case $ac_pass in 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; 2) as_fn_append ac_configure_args1 " '$ac_arg'" if test $ac_must_keep_next = true; then ac_must_keep_next=false # Got value, back to normal. else case $ac_arg in *=* | --config-cache | -C | -disable-* | --disable-* \ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ | -with-* | --with-* | -without-* | --without-* | --x) case "$ac_configure_args0 " in "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; esac ;; -* ) ac_must_keep_next=true ;; esac fi as_fn_append ac_configure_args " '$ac_arg'" ;; esac done done { ac_configure_args0=; unset ac_configure_args0;} { ac_configure_args1=; unset ac_configure_args1;} # When interrupted or exit'd, cleanup temporary files, and complete # config.log. We remove comments because anyway the quotes in there # would cause problems or look ugly. # WARNING: Use '\'' to represent an apostrophe within the trap. # WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. trap 'exit_status=$? # Sanitize IFS. IFS=" "" $as_nl" # Save into config.log some information that might help in debugging. { echo printf "%s\n" "## ---------------- ## ## Cache variables. ## ## ---------------- ##" echo # The following way of writing the cache mishandles newlines in values, ( for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 printf "%s\n" "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( *${as_nl}ac_space=\ *) sed -n \ "s/'\''/'\''\\\\'\'''\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" ;; #( *) sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) echo printf "%s\n" "## ----------------- ## ## Output variables. ## ## ----------------- ##" echo for ac_var in $ac_subst_vars do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`printf "%s\n" "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac printf "%s\n" "$ac_var='\''$ac_val'\''" done | sort echo if test -n "$ac_subst_files"; then printf "%s\n" "## ------------------- ## ## File substitutions. ## ## ------------------- ##" echo for ac_var in $ac_subst_files do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`printf "%s\n" "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac printf "%s\n" "$ac_var='\''$ac_val'\''" done | sort echo fi if test -s confdefs.h; then printf "%s\n" "## ----------- ## ## confdefs.h. ## ## ----------- ##" echo cat confdefs.h echo fi test "$ac_signal" != 0 && printf "%s\n" "$as_me: caught signal $ac_signal" printf "%s\n" "$as_me: exit $exit_status" } >&5 rm -f core *.core core.conftest.* && rm -f -r conftest* confdefs* conf$$* $ac_clean_files && exit $exit_status ' 0 for ac_signal in 1 2 13 15; do trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal done ac_signal=0 # confdefs.h avoids OS command line length limits that DEFS can exceed. rm -f -r conftest* confdefs.h printf "%s\n" "/* confdefs.h */" > confdefs.h # Predefined preprocessor variables. printf "%s\n" "#define PACKAGE_NAME \"$PACKAGE_NAME\"" >>confdefs.h printf "%s\n" "#define PACKAGE_TARNAME \"$PACKAGE_TARNAME\"" >>confdefs.h printf "%s\n" "#define PACKAGE_VERSION \"$PACKAGE_VERSION\"" >>confdefs.h printf "%s\n" "#define PACKAGE_STRING \"$PACKAGE_STRING\"" >>confdefs.h printf "%s\n" "#define PACKAGE_BUGREPORT \"$PACKAGE_BUGREPORT\"" >>confdefs.h printf "%s\n" "#define PACKAGE_URL \"$PACKAGE_URL\"" >>confdefs.h # Let the site file select an alternate cache file if it wants to. # Prefer an explicitly selected file to automatically selected ones. if test -n "$CONFIG_SITE"; then ac_site_files="$CONFIG_SITE" elif test "x$prefix" != xNONE; then ac_site_files="$prefix/share/config.site $prefix/etc/config.site" else ac_site_files="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site" fi for ac_site_file in $ac_site_files do case $ac_site_file in #( */*) : ;; #( *) : ac_site_file=./$ac_site_file ;; esac if test -f "$ac_site_file" && test -r "$ac_site_file"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 printf "%s\n" "$as_me: loading site script $ac_site_file" >&6;} sed 's/^/| /' "$ac_site_file" >&5 . "$ac_site_file" \ || { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "failed to load site script $ac_site_file See \`config.log' for more details" "$LINENO" 5; } fi done if test -r "$cache_file"; then # Some versions of bash will fail to source /dev/null (special files # actually), so we avoid doing that. DJGPP emulates it as a regular file. if test /dev/null != "$cache_file" && test -f "$cache_file"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 printf "%s\n" "$as_me: loading cache $cache_file" >&6;} case $cache_file in [\\/]* | ?:[\\/]* ) . "$cache_file";; *) . "./$cache_file";; esac fi else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 printf "%s\n" "$as_me: creating cache $cache_file" >&6;} >$cache_file fi # Test code for whether the C compiler supports C89 (global declarations) ac_c_conftest_c89_globals=' /* Does the compiler advertise C89 conformance? Do not test the value of __STDC__, because some compilers set it to 0 while being otherwise adequately conformant. */ #if !defined __STDC__ # error "Compiler does not advertise C89 conformance" #endif #include #include struct stat; /* Most of the following tests are stolen from RCS 5.7 src/conf.sh. */ struct buf { int x; }; struct buf * (*rcsopen) (struct buf *, struct stat *, int); static char *e (char **p, int i) { return p[i]; } static char *f (char * (*g) (char **, int), char **p, ...) { char *s; va_list v; va_start (v,p); s = g (p, va_arg (v,int)); va_end (v); return s; } /* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has function prototypes and stuff, but not \xHH hex character constants. These do not provoke an error unfortunately, instead are silently treated as an "x". The following induces an error, until -std is added to get proper ANSI mode. Curiously \x00 != x always comes out true, for an array size at least. It is necessary to write \x00 == 0 to get something that is true only with -std. */ int osf4_cc_array ['\''\x00'\'' == 0 ? 1 : -1]; /* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters inside strings and character constants. */ #define FOO(x) '\''x'\'' int xlc6_cc_array[FOO(a) == '\''x'\'' ? 1 : -1]; int test (int i, double x); struct s1 {int (*f) (int a);}; struct s2 {int (*f) (double a);}; int pairnames (int, char **, int *(*)(struct buf *, struct stat *, int), int, int);' # Test code for whether the C compiler supports C89 (body of main). ac_c_conftest_c89_main=' ok |= (argc == 0 || f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]); ' # Test code for whether the C compiler supports C99 (global declarations) ac_c_conftest_c99_globals=' // Does the compiler advertise C99 conformance? #if !defined __STDC_VERSION__ || __STDC_VERSION__ < 199901L # error "Compiler does not advertise C99 conformance" #endif #include extern int puts (const char *); extern int printf (const char *, ...); extern int dprintf (int, const char *, ...); extern void *malloc (size_t); extern void free (void *); // Check varargs macros. These examples are taken from C99 6.10.3.5. // dprintf is used instead of fprintf to avoid needing to declare // FILE and stderr. #define debug(...) dprintf (2, __VA_ARGS__) #define showlist(...) puts (#__VA_ARGS__) #define report(test,...) ((test) ? puts (#test) : printf (__VA_ARGS__)) static void test_varargs_macros (void) { int x = 1234; int y = 5678; debug ("Flag"); debug ("X = %d\n", x); showlist (The first, second, and third items.); report (x>y, "x is %d but y is %d", x, y); } // Check long long types. #define BIG64 18446744073709551615ull #define BIG32 4294967295ul #define BIG_OK (BIG64 / BIG32 == 4294967297ull && BIG64 % BIG32 == 0) #if !BIG_OK #error "your preprocessor is broken" #endif #if BIG_OK #else #error "your preprocessor is broken" #endif static long long int bignum = -9223372036854775807LL; static unsigned long long int ubignum = BIG64; struct incomplete_array { int datasize; double data[]; }; struct named_init { int number; const wchar_t *name; double average; }; typedef const char *ccp; static inline int test_restrict (ccp restrict text) { // See if C++-style comments work. // Iterate through items via the restricted pointer. // Also check for declarations in for loops. for (unsigned int i = 0; *(text+i) != '\''\0'\''; ++i) continue; return 0; } // Check varargs and va_copy. static bool test_varargs (const char *format, ...) { va_list args; va_start (args, format); va_list args_copy; va_copy (args_copy, args); const char *str = ""; int number = 0; float fnumber = 0; while (*format) { switch (*format++) { case '\''s'\'': // string str = va_arg (args_copy, const char *); break; case '\''d'\'': // int number = va_arg (args_copy, int); break; case '\''f'\'': // float fnumber = va_arg (args_copy, double); break; default: break; } } va_end (args_copy); va_end (args); return *str && number && fnumber; } ' # Test code for whether the C compiler supports C99 (body of main). ac_c_conftest_c99_main=' // Check bool. _Bool success = false; success |= (argc != 0); // Check restrict. if (test_restrict ("String literal") == 0) success = true; char *restrict newvar = "Another string"; // Check varargs. success &= test_varargs ("s, d'\'' f .", "string", 65, 34.234); test_varargs_macros (); // Check flexible array members. struct incomplete_array *ia = malloc (sizeof (struct incomplete_array) + (sizeof (double) * 10)); ia->datasize = 10; for (int i = 0; i < ia->datasize; ++i) ia->data[i] = i * 1.234; // Check named initializers. struct named_init ni = { .number = 34, .name = L"Test wide string", .average = 543.34343, }; ni.number = 58; int dynamic_array[ni.number]; dynamic_array[0] = argv[0][0]; dynamic_array[ni.number - 1] = 543; // work around unused variable warnings ok |= (!success || bignum == 0LL || ubignum == 0uLL || newvar[0] == '\''x'\'' || dynamic_array[ni.number - 1] != 543); ' # Test code for whether the C compiler supports C11 (global declarations) ac_c_conftest_c11_globals=' // Does the compiler advertise C11 conformance? #if !defined __STDC_VERSION__ || __STDC_VERSION__ < 201112L # error "Compiler does not advertise C11 conformance" #endif // Check _Alignas. char _Alignas (double) aligned_as_double; char _Alignas (0) no_special_alignment; extern char aligned_as_int; char _Alignas (0) _Alignas (int) aligned_as_int; // Check _Alignof. enum { int_alignment = _Alignof (int), int_array_alignment = _Alignof (int[100]), char_alignment = _Alignof (char) }; _Static_assert (0 < -_Alignof (int), "_Alignof is signed"); // Check _Noreturn. int _Noreturn does_not_return (void) { for (;;) continue; } // Check _Static_assert. struct test_static_assert { int x; _Static_assert (sizeof (int) <= sizeof (long int), "_Static_assert does not work in struct"); long int y; }; // Check UTF-8 literals. #define u8 syntax error! char const utf8_literal[] = u8"happens to be ASCII" "another string"; // Check duplicate typedefs. typedef long *long_ptr; typedef long int *long_ptr; typedef long_ptr long_ptr; // Anonymous structures and unions -- taken from C11 6.7.2.1 Example 1. struct anonymous { union { struct { int i; int j; }; struct { int k; long int l; } w; }; int m; } v1; ' # Test code for whether the C compiler supports C11 (body of main). ac_c_conftest_c11_main=' _Static_assert ((offsetof (struct anonymous, i) == offsetof (struct anonymous, w.k)), "Anonymous union alignment botch"); v1.i = 2; v1.w.k = 5; ok |= v1.i != 5; ' # Test code for whether the C compiler supports C11 (complete). ac_c_conftest_c11_program="${ac_c_conftest_c89_globals} ${ac_c_conftest_c99_globals} ${ac_c_conftest_c11_globals} int main (int argc, char **argv) { int ok = 0; ${ac_c_conftest_c89_main} ${ac_c_conftest_c99_main} ${ac_c_conftest_c11_main} return ok; } " # Test code for whether the C compiler supports C99 (complete). ac_c_conftest_c99_program="${ac_c_conftest_c89_globals} ${ac_c_conftest_c99_globals} int main (int argc, char **argv) { int ok = 0; ${ac_c_conftest_c89_main} ${ac_c_conftest_c99_main} return ok; } " # Test code for whether the C compiler supports C89 (complete). ac_c_conftest_c89_program="${ac_c_conftest_c89_globals} int main (int argc, char **argv) { int ok = 0; ${ac_c_conftest_c89_main} return ok; } " as_fn_append ac_header_c_list " stdio.h stdio_h HAVE_STDIO_H" as_fn_append ac_header_c_list " stdlib.h stdlib_h HAVE_STDLIB_H" as_fn_append ac_header_c_list " string.h string_h HAVE_STRING_H" as_fn_append ac_header_c_list " inttypes.h inttypes_h HAVE_INTTYPES_H" as_fn_append ac_header_c_list " stdint.h stdint_h HAVE_STDINT_H" as_fn_append ac_header_c_list " strings.h strings_h HAVE_STRINGS_H" as_fn_append ac_header_c_list " sys/stat.h sys_stat_h HAVE_SYS_STAT_H" as_fn_append ac_header_c_list " sys/types.h sys_types_h HAVE_SYS_TYPES_H" as_fn_append ac_header_c_list " unistd.h unistd_h HAVE_UNISTD_H" as_fn_append ac_header_c_list " sys/param.h sys_param_h HAVE_SYS_PARAM_H" as_fn_append ac_func_c_list " getpagesize HAVE_GETPAGESIZE" # Auxiliary files required by this configure script. ac_aux_files="config.guess config.sub install-sh" # Locations in which to look for auxiliary files. ac_aux_dir_candidates="${srcdir}${PATH_SEPARATOR}${srcdir}/..${PATH_SEPARATOR}${srcdir}/../.." # Search for a directory containing all of the required auxiliary files, # $ac_aux_files, from the $PATH-style list $ac_aux_dir_candidates. # If we don't find one directory that contains all the files we need, # we report the set of missing files from the *first* directory in # $ac_aux_dir_candidates and give up. ac_missing_aux_files="" ac_first_candidate=: printf "%s\n" "$as_me:${as_lineno-$LINENO}: looking for aux files: $ac_aux_files" >&5 as_save_IFS=$IFS; IFS=$PATH_SEPARATOR as_found=false for as_dir in $ac_aux_dir_candidates do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac as_found=: printf "%s\n" "$as_me:${as_lineno-$LINENO}: trying $as_dir" >&5 ac_aux_dir_found=yes ac_install_sh= for ac_aux in $ac_aux_files do # As a special case, if "install-sh" is required, that requirement # can be satisfied by any of "install-sh", "install.sh", or "shtool", # and $ac_install_sh is set appropriately for whichever one is found. if test x"$ac_aux" = x"install-sh" then if test -f "${as_dir}install-sh"; then printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}install-sh found" >&5 ac_install_sh="${as_dir}install-sh -c" elif test -f "${as_dir}install.sh"; then printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}install.sh found" >&5 ac_install_sh="${as_dir}install.sh -c" elif test -f "${as_dir}shtool"; then printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}shtool found" >&5 ac_install_sh="${as_dir}shtool install -c" else ac_aux_dir_found=no if $ac_first_candidate; then ac_missing_aux_files="${ac_missing_aux_files} install-sh" else break fi fi else if test -f "${as_dir}${ac_aux}"; then printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}${ac_aux} found" >&5 else ac_aux_dir_found=no if $ac_first_candidate; then ac_missing_aux_files="${ac_missing_aux_files} ${ac_aux}" else break fi fi fi done if test "$ac_aux_dir_found" = yes; then ac_aux_dir="$as_dir" break fi ac_first_candidate=false as_found=false done IFS=$as_save_IFS if $as_found then : else $as_nop as_fn_error $? "cannot find required auxiliary files:$ac_missing_aux_files" "$LINENO" 5 fi # These three variables are undocumented and unsupported, # and are intended to be withdrawn in a future Autoconf release. # They can cause serious problems if a builder's source tree is in a directory # whose full name contains unusual characters. if test -f "${ac_aux_dir}config.guess"; then ac_config_guess="$SHELL ${ac_aux_dir}config.guess" fi if test -f "${ac_aux_dir}config.sub"; then ac_config_sub="$SHELL ${ac_aux_dir}config.sub" fi if test -f "$ac_aux_dir/configure"; then ac_configure="$SHELL ${ac_aux_dir}configure" fi # Check that the precious variables saved in the cache have kept the same # value. ac_cache_corrupted=false for ac_var in $ac_precious_vars; do eval ac_old_set=\$ac_cv_env_${ac_var}_set eval ac_new_set=\$ac_env_${ac_var}_set eval ac_old_val=\$ac_cv_env_${ac_var}_value eval ac_new_val=\$ac_env_${ac_var}_value case $ac_old_set,$ac_new_set in set,) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 printf "%s\n" "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} ac_cache_corrupted=: ;; ,set) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 printf "%s\n" "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} ac_cache_corrupted=: ;; ,);; *) if test "x$ac_old_val" != "x$ac_new_val"; then # differences in whitespace do not lead to failure. ac_old_val_w=`echo x $ac_old_val` ac_new_val_w=`echo x $ac_new_val` if test "$ac_old_val_w" != "$ac_new_val_w"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 printf "%s\n" "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} ac_cache_corrupted=: else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 printf "%s\n" "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} eval $ac_var=\$ac_old_val fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 printf "%s\n" "$as_me: former value: \`$ac_old_val'" >&2;} { printf "%s\n" "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 printf "%s\n" "$as_me: current value: \`$ac_new_val'" >&2;} fi;; esac # Pass precious variables to config.status. if test "$ac_new_set" = set; then case $ac_new_val in *\'*) ac_arg=$ac_var=`printf "%s\n" "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; *) ac_arg=$ac_var=$ac_new_val ;; esac case " $ac_configure_args " in *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. *) as_fn_append ac_configure_args " '$ac_arg'" ;; esac fi done if $ac_cache_corrupted; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 printf "%s\n" "$as_me: error: changes in the environment can compromise the build" >&2;} as_fn_error $? "run \`${MAKE-make} distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 fi ## -------------------- ## ## Main body of script. ## ## -------------------- ## ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu PACKAGE_ABIVERS=0.6 ac_config_headers="$ac_config_headers src/config.h" # Checks for programs. ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. set dummy ${ac_tool_prefix}gcc; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}gcc" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="gcc" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 printf "%s\n" "$ac_ct_CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi else CC="$ac_cv_prog_CC" fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. set dummy ${ac_tool_prefix}cc; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}cc" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi fi if test -z "$CC"; then # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else ac_prog_rejected=no as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then if test "$as_dir$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then ac_prog_rejected=yes continue fi ac_cv_prog_CC="cc" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS if test $ac_prog_rejected = yes; then # We found a bogon in the path, so make sure we never use it. set dummy $ac_cv_prog_CC shift if test $# != 0; then # We chose a different compiler from the bogus one. # However, it has the same basename, so the bogon will be chosen # first if we set CC to just the basename; use the full file name. shift ac_cv_prog_CC="$as_dir$ac_word${1+' '}$@" fi fi fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then for ac_prog in cl.exe do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CC="$ac_tool_prefix$ac_prog" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi test -n "$CC" && break done fi if test -z "$CC"; then ac_ct_CC=$CC for ac_prog in cl.exe do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="$ac_prog" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 printf "%s\n" "$ac_ct_CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi test -n "$ac_ct_CC" && break done if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi fi fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}clang", so it can be a program name with args. set dummy ${ac_tool_prefix}clang; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}clang" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "clang", so it can be a program name with args. set dummy clang; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="clang" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 printf "%s\n" "$ac_ct_CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi else CC="$ac_cv_prog_CC" fi fi test -z "$CC" && { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "no acceptable C compiler found in \$PATH See \`config.log' for more details" "$LINENO" 5; } # Provide some information about the compiler. printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 set X $ac_compile ac_compiler=$2 for ac_option in --version -v -V -qversion -version; do { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then sed '10a\ ... rest of stderr output deleted ... 10q' conftest.err >conftest.er1 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" # Try to create an executable without -o first, disregard a.out. # It will help us diagnose broken compilers, and finding out an intuition # of exeext. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 printf %s "checking whether the C compiler works... " >&6; } ac_link_default=`printf "%s\n" "$ac_link" | sed 's/ -o *conftest[^ ]*//'` # The possible output files: ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" ac_rmfiles= for ac_file in $ac_files do case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; * ) ac_rmfiles="$ac_rmfiles $ac_file";; esac done rm -f $ac_rmfiles if { { ac_try="$ac_link_default" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_link_default") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } then : # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. # So ignore a value of `no', otherwise this would lead to `EXEEXT = no' # in a Makefile. We should not override ac_cv_exeext if it was cached, # so that the user can short-circuit this test for compilers unknown to # Autoconf. for ac_file in $ac_files '' do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; [ab].out ) # We found the default executable, but exeext='' is most # certainly right. break;; *.* ) if test ${ac_cv_exeext+y} && test "$ac_cv_exeext" != no; then :; else ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` fi # We set ac_cv_exeext here because the later test for it is not # safe: cross compilers may not add the suffix if given an `-o' # argument, so we may need to know it at that point already. # Even if this section looks crufty: it has the advantage of # actually working. break;; * ) break;; esac done test "$ac_cv_exeext" = no && ac_cv_exeext= else $as_nop ac_file='' fi if test -z "$ac_file" then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "C compiler cannot create executables See \`config.log' for more details" "$LINENO" 5; } else $as_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 printf %s "checking for C compiler default output file name... " >&6; } { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 printf "%s\n" "$ac_file" >&6; } ac_exeext=$ac_cv_exeext rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out ac_clean_files=$ac_clean_files_save { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 printf %s "checking for suffix of executables... " >&6; } if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } then : # If both `conftest.exe' and `conftest' are `present' (well, observable) # catch `conftest.exe'. For instance with Cygwin, `ls conftest' will # work properly (i.e., refer to `conftest.exe'), while it won't with # `rm'. for ac_file in conftest.exe conftest conftest.*; do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` break;; * ) break;; esac done else $as_nop { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of executables: cannot compile and link See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest conftest$ac_cv_exeext { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 printf "%s\n" "$ac_cv_exeext" >&6; } rm -f conftest.$ac_ext EXEEXT=$ac_cv_exeext ac_exeext=$EXEEXT cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main (void) { FILE *f = fopen ("conftest.out", "w"); return ferror (f) || fclose (f) != 0; ; return 0; } _ACEOF ac_clean_files="$ac_clean_files conftest.out" # Check that the compiler produces executables we can run. If not, either # the compiler is broken, or we cross compile. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 printf %s "checking whether we are cross compiling... " >&6; } if test "$cross_compiling" != yes; then { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if { ac_try='./conftest$ac_cv_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then cross_compiling=no else if test "$cross_compiling" = maybe; then cross_compiling=yes else { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot run C compiled programs. If you meant to cross compile, use \`--host'. See \`config.log' for more details" "$LINENO" 5; } fi fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 printf "%s\n" "$cross_compiling" >&6; } rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out ac_clean_files=$ac_clean_files_save { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 printf %s "checking for suffix of object files... " >&6; } if test ${ac_cv_objext+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF rm -f conftest.o conftest.obj if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } then : for ac_file in conftest.o conftest.obj conftest.*; do test -f "$ac_file" || continue; case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` break;; esac done else $as_nop printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of object files: cannot compile See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest.$ac_cv_objext conftest.$ac_ext fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 printf "%s\n" "$ac_cv_objext" >&6; } OBJEXT=$ac_cv_objext ac_objext=$OBJEXT { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports GNU C" >&5 printf %s "checking whether the compiler supports GNU C... " >&6; } if test ${ac_cv_c_compiler_gnu+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_compiler_gnu=yes else $as_nop ac_compiler_gnu=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ac_cv_c_compiler_gnu=$ac_compiler_gnu fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 printf "%s\n" "$ac_cv_c_compiler_gnu" >&6; } ac_compiler_gnu=$ac_cv_c_compiler_gnu if test $ac_compiler_gnu = yes; then GCC=yes else GCC= fi ac_test_CFLAGS=${CFLAGS+y} ac_save_CFLAGS=$CFLAGS { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 printf %s "checking whether $CC accepts -g... " >&6; } if test ${ac_cv_prog_cc_g+y} then : printf %s "(cached) " >&6 else $as_nop ac_save_c_werror_flag=$ac_c_werror_flag ac_c_werror_flag=yes ac_cv_prog_cc_g=no CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_g=yes else $as_nop CFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : else $as_nop ac_c_werror_flag=$ac_save_c_werror_flag CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_g=yes fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ac_c_werror_flag=$ac_save_c_werror_flag fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 printf "%s\n" "$ac_cv_prog_cc_g" >&6; } if test $ac_test_CFLAGS; then CFLAGS=$ac_save_CFLAGS elif test $ac_cv_prog_cc_g = yes; then if test "$GCC" = yes; then CFLAGS="-g -O2" else CFLAGS="-g" fi else if test "$GCC" = yes; then CFLAGS="-O2" else CFLAGS= fi fi ac_prog_cc_stdc=no if test x$ac_prog_cc_stdc = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C11 features" >&5 printf %s "checking for $CC option to enable C11 features... " >&6; } if test ${ac_cv_prog_cc_c11+y} then : printf %s "(cached) " >&6 else $as_nop ac_cv_prog_cc_c11=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_c_conftest_c11_program _ACEOF for ac_arg in '' -std=gnu11 do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_c11=$ac_arg fi rm -f core conftest.err conftest.$ac_objext conftest.beam test "x$ac_cv_prog_cc_c11" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi if test "x$ac_cv_prog_cc_c11" = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 printf "%s\n" "unsupported" >&6; } else $as_nop if test "x$ac_cv_prog_cc_c11" = x then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 printf "%s\n" "none needed" >&6; } else $as_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c11" >&5 printf "%s\n" "$ac_cv_prog_cc_c11" >&6; } CC="$CC $ac_cv_prog_cc_c11" fi ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c11 ac_prog_cc_stdc=c11 fi fi if test x$ac_prog_cc_stdc = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C99 features" >&5 printf %s "checking for $CC option to enable C99 features... " >&6; } if test ${ac_cv_prog_cc_c99+y} then : printf %s "(cached) " >&6 else $as_nop ac_cv_prog_cc_c99=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_c_conftest_c99_program _ACEOF for ac_arg in '' -std=gnu99 -std=c99 -c99 -qlanglvl=extc1x -qlanglvl=extc99 -AC99 -D_STDC_C99= do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_c99=$ac_arg fi rm -f core conftest.err conftest.$ac_objext conftest.beam test "x$ac_cv_prog_cc_c99" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi if test "x$ac_cv_prog_cc_c99" = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 printf "%s\n" "unsupported" >&6; } else $as_nop if test "x$ac_cv_prog_cc_c99" = x then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 printf "%s\n" "none needed" >&6; } else $as_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c99" >&5 printf "%s\n" "$ac_cv_prog_cc_c99" >&6; } CC="$CC $ac_cv_prog_cc_c99" fi ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c99 ac_prog_cc_stdc=c99 fi fi if test x$ac_prog_cc_stdc = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C89 features" >&5 printf %s "checking for $CC option to enable C89 features... " >&6; } if test ${ac_cv_prog_cc_c89+y} then : printf %s "(cached) " >&6 else $as_nop ac_cv_prog_cc_c89=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_c_conftest_c89_program _ACEOF for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_c89=$ac_arg fi rm -f core conftest.err conftest.$ac_objext conftest.beam test "x$ac_cv_prog_cc_c89" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi if test "x$ac_cv_prog_cc_c89" = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 printf "%s\n" "unsupported" >&6; } else $as_nop if test "x$ac_cv_prog_cc_c89" = x then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 printf "%s\n" "none needed" >&6; } else $as_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 printf "%s\n" "$ac_cv_prog_cc_c89" >&6; } CC="$CC $ac_cv_prog_cc_c89" fi ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c89 ac_prog_cc_stdc=c89 fi fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu # Find a good install program. We prefer a C program (faster), # so one script is as good as another. But avoid the broken or # incompatible versions: # SysV /etc/install, /usr/sbin/install # SunOS /usr/etc/install # IRIX /sbin/install # AIX /bin/install # AmigaOS /C/install, which installs bootblocks on floppy discs # AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag # AFS /usr/afsws/bin/install, which mishandles nonexistent args # SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" # OS/2's system install, which has a completely different semantic # ./install, which can be erroneously created by make from ./install.sh. # Reject install programs that cannot install multiple files. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 printf %s "checking for a BSD-compatible install... " >&6; } if test -z "$INSTALL"; then if test ${ac_cv_path_install+y} then : printf %s "(cached) " >&6 else $as_nop as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac # Account for fact that we put trailing slashes in our PATH walk. case $as_dir in #(( ./ | /[cC]/* | \ /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \ /usr/ucb/* ) ;; *) # OSF1 and SCO ODT 3.0 have their own names for install. # Don't use installbsd from OSF since it installs stuff as root # by default. for ac_prog in ginstall scoinst install; do for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_prog$ac_exec_ext"; then if test $ac_prog = install && grep dspmsg "$as_dir$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # AIX install. It has an incompatible calling convention. : elif test $ac_prog = install && grep pwplus "$as_dir$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # program-specific install script used by HP pwplus--don't use. : else rm -rf conftest.one conftest.two conftest.dir echo one > conftest.one echo two > conftest.two mkdir conftest.dir if "$as_dir$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir/" && test -s conftest.one && test -s conftest.two && test -s conftest.dir/conftest.one && test -s conftest.dir/conftest.two then ac_cv_path_install="$as_dir$ac_prog$ac_exec_ext -c" break 3 fi fi fi done done ;; esac done IFS=$as_save_IFS rm -rf conftest.one conftest.two conftest.dir fi if test ${ac_cv_path_install+y}; then INSTALL=$ac_cv_path_install else # As a last resort, use the slow shell script. Don't cache a # value for INSTALL within a source directory, because that will # break other packages using the cache if that directory is # removed, or if the value is a relative name. INSTALL=$ac_install_sh fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5 printf "%s\n" "$INSTALL" >&6; } # Use test -z because SunOS4 sh mishandles braces in ${var-val}. # It thinks the first close brace ends the variable substitution. test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether ln -s works" >&5 printf %s "checking whether ln -s works... " >&6; } LN_S=$as_ln_s if test "$LN_S" = "ln -s"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no, using $LN_S" >&5 printf "%s\n" "no, using $LN_S" >&6; } fi # Extract the first word of "lctest", so it can be a program name with args. set dummy lctest; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_testrunner+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$testrunner"; then ac_cv_prog_testrunner="$testrunner" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_testrunner="lctest" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_prog_testrunner" && ac_cv_prog_testrunner="maketest" fi fi testrunner=$ac_cv_prog_testrunner if test -n "$testrunner"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $testrunner" >&5 printf "%s\n" "$testrunner" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi TESTRUNNER=$testrunner for ac_prog in false do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_FALSE+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$FALSE"; then ac_cv_prog_FALSE="$FALSE" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_FALSE="$ac_prog" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi FALSE=$ac_cv_prog_FALSE if test -n "$FALSE"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $FALSE" >&5 printf "%s\n" "$FALSE" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi test -n "$FALSE" && break done test -n "$FALSE" || FALSE="/usr/bin/env false" # Extract the first word of "ifconfig", so it can be a program name with args. set dummy ifconfig; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ifconfig+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$ifconfig"; then ac_cv_prog_ifconfig="$ifconfig" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ifconfig="ifconfig" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ifconfig=$ac_cv_prog_ifconfig if test -n "$ifconfig"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ifconfig" >&5 printf "%s\n" "$ifconfig" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi IFCONFIG=$ifconfig # Extract the first word of "ip", so it can be a program name with args. set dummy ip; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_iproute+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$iproute"; then ac_cv_prog_iproute="$iproute" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_iproute="iproute" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi iproute=$ac_cv_prog_iproute if test -n "$iproute"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $iproute" >&5 printf "%s\n" "$iproute" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi IPROUTE=$iproute # Extract the first word of "route", so it can be a program name with args. set dummy route; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ROUTE+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$ROUTE"; then ac_cv_prog_ROUTE="$ROUTE" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ROUTE="route" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ROUTE=$ac_cv_prog_ROUTE if test -n "$ROUTE"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ROUTE" >&5 printf "%s\n" "$ROUTE" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi # Checks for libraries. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for dlsym in -ldl" >&5 printf %s "checking for dlsym in -ldl... " >&6; } if test ${ac_cv_lib_dl_dlsym+y} then : printf %s "(cached) " >&6 else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-ldl $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. The 'extern "C"' is for builds by C++ compilers; although this is not generally supported in C code supporting it here has little cost and some practical benefit (sr 110532). */ #ifdef __cplusplus extern "C" #endif char dlsym (void); int main (void) { return dlsym (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_dl_dlsym=yes else $as_nop ac_cv_lib_dl_dlsym=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlsym" >&5 printf "%s\n" "$ac_cv_lib_dl_dlsym" >&6; } if test "x$ac_cv_lib_dl_dlsym" = xyes then : printf "%s\n" "#define HAVE_LIBDL 1" >>confdefs.h LIBS="-ldl $LIBS" fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for log2 in -lm" >&5 printf %s "checking for log2 in -lm... " >&6; } if test ${ac_cv_lib_m_log2+y} then : printf %s "(cached) " >&6 else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lm $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. The 'extern "C"' is for builds by C++ compilers; although this is not generally supported in C code supporting it here has little cost and some practical benefit (sr 110532). */ #ifdef __cplusplus extern "C" #endif char log2 (void); int main (void) { return log2 (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_m_log2=yes else $as_nop ac_cv_lib_m_log2=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_m_log2" >&5 printf "%s\n" "$ac_cv_lib_m_log2" >&6; } if test "x$ac_cv_lib_m_log2" = xyes then : printf "%s\n" "#define HAVE_LIBM 1" >>confdefs.h LIBS="-lm $LIBS" fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for pthread_create in -lpthread" >&5 printf %s "checking for pthread_create in -lpthread... " >&6; } if test ${ac_cv_lib_pthread_pthread_create+y} then : printf %s "(cached) " >&6 else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lpthread $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. The 'extern "C"' is for builds by C++ compilers; although this is not generally supported in C code supporting it here has little cost and some practical benefit (sr 110532). */ #ifdef __cplusplus extern "C" #endif char pthread_create (void); int main (void) { return pthread_create (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_pthread_pthread_create=yes else $as_nop ac_cv_lib_pthread_pthread_create=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthread_pthread_create" >&5 printf "%s\n" "$ac_cv_lib_pthread_pthread_create" >&6; } if test "x$ac_cv_lib_pthread_pthread_create" = xyes then : printf "%s\n" "#define HAVE_LIBPTHREAD 1" >>confdefs.h LIBS="-lpthread $LIBS" fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing arc4random_uniform" >&5 printf %s "checking for library containing arc4random_uniform... " >&6; } if test ${ac_cv_search_arc4random_uniform+y} then : printf %s "(cached) " >&6 else $as_nop ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. The 'extern "C"' is for builds by C++ compilers; although this is not generally supported in C code supporting it here has little cost and some practical benefit (sr 110532). */ #ifdef __cplusplus extern "C" #endif char arc4random_uniform (void); int main (void) { return arc4random_uniform (); ; return 0; } _ACEOF for ac_lib in '' bsd do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO" then : ac_cv_search_arc4random_uniform=$ac_res fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext if test ${ac_cv_search_arc4random_uniform+y} then : break fi done if test ${ac_cv_search_arc4random_uniform+y} then : else $as_nop ac_cv_search_arc4random_uniform=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_arc4random_uniform" >&5 printf "%s\n" "$ac_cv_search_arc4random_uniform" >&6; } ac_res=$ac_cv_search_arc4random_uniform if test "$ac_res" != no then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing clock_gettime" >&5 printf %s "checking for library containing clock_gettime... " >&6; } if test ${ac_cv_search_clock_gettime+y} then : printf %s "(cached) " >&6 else $as_nop ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. The 'extern "C"' is for builds by C++ compilers; although this is not generally supported in C code supporting it here has little cost and some practical benefit (sr 110532). */ #ifdef __cplusplus extern "C" #endif char clock_gettime (void); int main (void) { return clock_gettime (); ; return 0; } _ACEOF for ac_lib in '' rt do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO" then : ac_cv_search_clock_gettime=$ac_res fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext if test ${ac_cv_search_clock_gettime+y} then : break fi done if test ${ac_cv_search_clock_gettime+y} then : else $as_nop ac_cv_search_clock_gettime=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_clock_gettime" >&5 printf "%s\n" "$ac_cv_search_clock_gettime" >&6; } ac_res=$ac_cv_search_clock_gettime if test "$ac_res" != no then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing __atomic_load_8" >&5 printf %s "checking for library containing __atomic_load_8... " >&6; } if test ${ac_cv_search___atomic_load_8+y} then : printf %s "(cached) " >&6 else $as_nop ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. The 'extern "C"' is for builds by C++ compilers; although this is not generally supported in C code supporting it here has little cost and some practical benefit (sr 110532). */ #ifdef __cplusplus extern "C" #endif char __atomic_load_8 (void); int main (void) { return __atomic_load_8 (); ; return 0; } _ACEOF for ac_lib in '' atomic do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO" then : ac_cv_search___atomic_load_8=$ac_res fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext if test ${ac_cv_search___atomic_load_8+y} then : break fi done if test ${ac_cv_search___atomic_load_8+y} then : else $as_nop ac_cv_search___atomic_load_8=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search___atomic_load_8" >&5 printf "%s\n" "$ac_cv_search___atomic_load_8" >&6; } ac_res=$ac_cv_search___atomic_load_8 if test "$ac_res" != no then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" fi # Check whether --with-mld was given. if test ${with_mld+y} then : withval=$with_mld; fi # Check whether --with-blake3 was given. if test ${with_blake3+y} then : withval=$with_blake3; fi LIBBLAKE3= if test "x$with_blake3" != xno then : BLAKE3=blake3 LIBBLAKE3=-lblake3 INCBLAKE3="#include " printf "%s\n" "#define HAVE_BLAKE3 1" >>confdefs.h fi LIBMLD= if test "x$with_mld" != "xno" then : MLD=libmld LIBMLD=-lmld OBJMLD=../libs/libmld/src/*.o MLD_HEADERS=../libs/libmld/include/*.h INCMLD="-I ../libs/libmld" printf "%s\n" "#define HAVE_MLD 1" >>confdefs.h fi # Check whether --with-sodium was given. if test ${with_sodium+y} then : withval=$with_sodium; else $as_nop with_sodium=check fi LIBSODIUM= if test "x$with_sodium" != xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for sodium_init in -lsodium" >&5 printf %s "checking for sodium_init in -lsodium... " >&6; } if test ${ac_cv_lib_sodium_sodium_init+y} then : printf %s "(cached) " >&6 else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lsodium -lsodium $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. The 'extern "C"' is for builds by C++ compilers; although this is not generally supported in C code supporting it here has little cost and some practical benefit (sr 110532). */ #ifdef __cplusplus extern "C" #endif char sodium_init (void); int main (void) { return sodium_init (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_sodium_sodium_init=yes else $as_nop ac_cv_lib_sodium_sodium_init=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_sodium_sodium_init" >&5 printf "%s\n" "$ac_cv_lib_sodium_sodium_init" >&6; } if test "x$ac_cv_lib_sodium_sodium_init" = xyes then : LIBSODIUM="-lsodium" INCSODIUM="#include " HAVE_LIBSODIUM="HAVE_LIBSODIUM := 1" printf "%s\n" "#define HAVE_LIBSODIUM 1" >>confdefs.h else $as_nop if test "x$with_sodium" != xcheck; then { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "--with-sodium was given, but libsodium not found See \`config.log' for more details" "$LINENO" 5; } fi fi fi if test "x$with_blake3" != xno then : HASH_TYPE="#define HASH_TYPE HASH_BLAKE3" HASHSIZE="#define HASHSIZE BLAKE3_OUT_LEN" HASH_STATE="typedef blake3_hasher hash_state;" else $as_nop if test "x$with_sodium" != xno then : HASH_TYPE="#define HASH_TYPE HASH_BLAKE2" HASHSIZE="#define HASHSIZE crypto_generichash_BYTES" HASH_STATE="typedef crypto_generichash_state hash_state;" else $as_nop HASH_TYPE="#undef HASH_TYPE" HASHSIZE="#undef HASHSIZE" fi fi # Check whether --with-lcrq was given. if test ${with_lcrq+y} then : withval=$with_lcrq; else $as_nop with_lcrq=check fi LIBLCRQ= if test "x$with_lcrq" != xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for rq_init in -llcrq" >&5 printf %s "checking for rq_init in -llcrq... " >&6; } if test ${ac_cv_lib_lcrq_rq_init+y} then : printf %s "(cached) " >&6 else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-llcrq -llcrq $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. The 'extern "C"' is for builds by C++ compilers; although this is not generally supported in C code supporting it here has little cost and some practical benefit (sr 110532). */ #ifdef __cplusplus extern "C" #endif char rq_init (void); int main (void) { return rq_init (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_lcrq_rq_init=yes else $as_nop ac_cv_lib_lcrq_rq_init=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_lcrq_rq_init" >&5 printf "%s\n" "$ac_cv_lib_lcrq_rq_init" >&6; } if test "x$ac_cv_lib_lcrq_rq_init" = xyes then : LIBLCRQ="-llcrq" INCLUDE_LCRQ="#include " HAVE_LIBLCRQ="HAVE_LIBLCRQ := 1" printf "%s\n" "#define HAVE_LIBLCRQ 1" >>confdefs.h else $as_nop if test "x$with_lcrq" != xcheck; then { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "--with-lcrq was given, but liblcrq not found See \`config.log' for more details" "$LINENO" 5; } fi fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for rq_init in -llcrq" >&5 printf %s "checking for rq_init in -llcrq... " >&6; } if test ${ac_cv_lib_lcrq_rq_init+y} then : printf %s "(cached) " >&6 else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-llcrq $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. The 'extern "C"' is for builds by C++ compilers; although this is not generally supported in C code supporting it here has little cost and some practical benefit (sr 110532). */ #ifdef __cplusplus extern "C" #endif char rq_init (void); int main (void) { return rq_init (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_lcrq_rq_init=yes else $as_nop ac_cv_lib_lcrq_rq_init=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_lcrq_rq_init" >&5 printf "%s\n" "$ac_cv_lib_lcrq_rq_init" >&6; } if test "x$ac_cv_lib_lcrq_rq_init" = xyes then : printf "%s\n" "#define HAVE_LIBLCRQ 1" >>confdefs.h LIBS="-llcrq $LIBS" fi ac_fn_c_check_func "$LINENO" "rq_oti" "ac_cv_func_rq_oti" if test "x$ac_cv_func_rq_oti" = xyes then : printf "%s\n" "#define HAVE_RQ_OTI 1" >>confdefs.h fi # Checks for header files. ac_header= ac_cache= for ac_item in $ac_header_c_list do if test $ac_cache; then ac_fn_c_check_header_compile "$LINENO" $ac_header ac_cv_header_$ac_cache "$ac_includes_default" if eval test \"x\$ac_cv_header_$ac_cache\" = xyes; then printf "%s\n" "#define $ac_item 1" >> confdefs.h fi ac_header= ac_cache= elif test $ac_header; then ac_cache=$ac_item else ac_header=$ac_item fi done if test $ac_cv_header_stdlib_h = yes && test $ac_cv_header_string_h = yes then : printf "%s\n" "#define STDC_HEADERS 1" >>confdefs.h fi for ac_header in arpa/inet.h fcntl.h netdb.h netinet/in.h stdint.h sys/ioctl.h sys/param.h sys/socket.h unistd.h do : as_ac_Header=`printf "%s\n" "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" if eval test \"x\$"$as_ac_Header"\" = x"yes" then : cat >>confdefs.h <<_ACEOF #define `printf "%s\n" "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF else $as_nop as_fn_error $? "required header file missing" "$LINENO" 5 fi done ac_fn_c_check_header_compile "$LINENO" "endian.h" "ac_cv_header_endian_h" "$ac_includes_default" if test "x$ac_cv_header_endian_h" = xyes then : printf "%s\n" "#define HAVE_ENDIAN_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "sys/endian.h" "ac_cv_header_sys_endian_h" "$ac_includes_default" if test "x$ac_cv_header_sys_endian_h" = xyes then : printf "%s\n" "#define HAVE_SYS_ENDIAN_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "libkern/OSByteOrder.h" "ac_cv_header_libkern_OSByteOrder_h" "$ac_includes_default" if test "x$ac_cv_header_libkern_OSByteOrder_h" = xyes then : printf "%s\n" "#define HAVE_LIBKERN_OSBYTEORDER_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "net/if_tap.h" "ac_cv_header_net_if_tap_h" "$ac_includes_default" if test "x$ac_cv_header_net_if_tap_h" = xyes then : printf "%s\n" "#define HAVE_NET_IF_TAP_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "net/if_tun.h" "ac_cv_header_net_if_tun_h" "$ac_includes_default" if test "x$ac_cv_header_net_if_tun_h" = xyes then : printf "%s\n" "#define HAVE_NET_IF_TUN_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "sys/time.h" "ac_cv_header_sys_time_h" "$ac_includes_default" if test "x$ac_cv_header_sys_time_h" = xyes then : printf "%s\n" "#define HAVE_SYS_TIME_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "utime.h" "ac_cv_header_utime_h" "$ac_includes_default" if test "x$ac_cv_header_utime_h" = xyes then : printf "%s\n" "#define HAVE_UTIME_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "linux/netlink.h" "ac_cv_header_linux_netlink_h" "$ac_includes_default" if test "x$ac_cv_header_linux_netlink_h" = xyes then : printf "%s\n" "#define HAVE_LINUX_NETLINK_H 1" >>confdefs.h fi ac_fn_c_check_type "$LINENO" "_Bool" "ac_cv_type__Bool" "$ac_includes_default" if test "x$ac_cv_type__Bool" = xyes then : printf "%s\n" "#define HAVE__BOOL 1" >>confdefs.h fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for stdbool.h that conforms to C99" >&5 printf %s "checking for stdbool.h that conforms to C99... " >&6; } if test ${ac_cv_header_stdbool_h+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #ifndef __bool_true_false_are_defined #error "__bool_true_false_are_defined is not defined" #endif char a[__bool_true_false_are_defined == 1 ? 1 : -1]; /* Regardless of whether this is C++ or "_Bool" is a valid type name, "true" and "false" should be usable in #if expressions and integer constant expressions, and "bool" should be a valid type name. */ #if !true #error "'true' is not true" #endif #if true != 1 #error "'true' is not equal to 1" #endif char b[true == 1 ? 1 : -1]; char c[true]; #if false #error "'false' is not false" #endif #if false != 0 #error "'false' is not equal to 0" #endif char d[false == 0 ? 1 : -1]; enum { e = false, f = true, g = false * true, h = true * 256 }; char i[(bool) 0.5 == true ? 1 : -1]; char j[(bool) 0.0 == false ? 1 : -1]; char k[sizeof (bool) > 0 ? 1 : -1]; struct sb { bool s: 1; bool t; } s; char l[sizeof s.t > 0 ? 1 : -1]; /* The following fails for HP aC++/ANSI C B3910B A.05.55 [Dec 04 2003]. */ bool m[h]; char n[sizeof m == h * sizeof m[0] ? 1 : -1]; char o[-1 - (bool) 0 < 0 ? 1 : -1]; /* Catch a bug in an HP-UX C compiler. See https://gcc.gnu.org/ml/gcc-patches/2003-12/msg02303.html https://lists.gnu.org/archive/html/bug-coreutils/2005-11/msg00161.html */ bool p = true; bool *pp = &p; /* C 1999 specifies that bool, true, and false are to be macros, but C++ 2011 and later overrule this. */ #if __cplusplus < 201103 #ifndef bool #error "bool is not defined" #endif #ifndef false #error "false is not defined" #endif #ifndef true #error "true is not defined" #endif #endif /* If _Bool is available, repeat with it all the tests above that used bool. */ #ifdef HAVE__BOOL struct sB { _Bool s: 1; _Bool t; } t; char q[(_Bool) 0.5 == true ? 1 : -1]; char r[(_Bool) 0.0 == false ? 1 : -1]; char u[sizeof (_Bool) > 0 ? 1 : -1]; char v[sizeof t.t > 0 ? 1 : -1]; _Bool w[h]; char x[sizeof m == h * sizeof m[0] ? 1 : -1]; char y[-1 - (_Bool) 0 < 0 ? 1 : -1]; _Bool z = true; _Bool *pz = &p; #endif int main (void) { bool ps = &s; *pp |= p; *pp |= ! p; #ifdef HAVE__BOOL _Bool pt = &t; *pz |= z; *pz |= ! z; #endif /* Refer to every declared value, so they cannot be discarded as unused. */ return (!a + !b + !c + !d + !e + !f + !g + !h + !i + !j + !k + !l + !m + !n + !o + !p + !pp + !ps #ifdef HAVE__BOOL + !q + !r + !u + !v + !w + !x + !y + !z + !pt #endif ); ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_header_stdbool_h=yes else $as_nop ac_cv_header_stdbool_h=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdbool_h" >&5 printf "%s\n" "$ac_cv_header_stdbool_h" >&6; } # Checks for typedefs, structures, and compiler characteristics. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for inline" >&5 printf %s "checking for inline... " >&6; } if test ${ac_cv_c_inline+y} then : printf %s "(cached) " >&6 else $as_nop ac_cv_c_inline=no for ac_kw in inline __inline__ __inline; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifndef __cplusplus typedef int foo_t; static $ac_kw foo_t static_foo (void) {return 0; } $ac_kw foo_t foo (void) {return 0; } #endif _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_c_inline=$ac_kw fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext test "$ac_cv_c_inline" != no && break done fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_inline" >&5 printf "%s\n" "$ac_cv_c_inline" >&6; } case $ac_cv_c_inline in inline | yes) ;; *) case $ac_cv_c_inline in no) ac_val=;; *) ac_val=$ac_cv_c_inline;; esac cat >>confdefs.h <<_ACEOF #ifndef __cplusplus #define inline $ac_val #endif _ACEOF ;; esac { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for C/C++ restrict keyword" >&5 printf %s "checking for C/C++ restrict keyword... " >&6; } if test ${ac_cv_c_restrict+y} then : printf %s "(cached) " >&6 else $as_nop ac_cv_c_restrict=no # Put '__restrict__' first, to avoid problems with glibc and non-GCC; see: # https://lists.gnu.org/archive/html/bug-autoconf/2016-02/msg00006.html # Put 'restrict' last, because C++ lacks it. for ac_kw in __restrict__ __restrict _Restrict restrict; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ typedef int *int_ptr; int foo (int_ptr $ac_kw ip) { return ip[0]; } int bar (int [$ac_kw]); /* Catch GCC bug 14050. */ int bar (int ip[$ac_kw]) { return ip[0]; } int main (void) { int s[1]; int *$ac_kw t = s; t[0] = 0; return foo (t) + bar (t); ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_c_restrict=$ac_kw fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext test "$ac_cv_c_restrict" != no && break done fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_restrict" >&5 printf "%s\n" "$ac_cv_c_restrict" >&6; } case $ac_cv_c_restrict in restrict) ;; no) printf "%s\n" "#define restrict /**/" >>confdefs.h ;; *) printf "%s\n" "#define restrict $ac_cv_c_restrict" >>confdefs.h ;; esac ac_fn_c_find_intX_t "$LINENO" "16" "ac_cv_c_int16_t" case $ac_cv_c_int16_t in #( no|yes) ;; #( *) printf "%s\n" "#define int16_t $ac_cv_c_int16_t" >>confdefs.h ;; esac ac_fn_c_find_intX_t "$LINENO" "32" "ac_cv_c_int32_t" case $ac_cv_c_int32_t in #( no|yes) ;; #( *) printf "%s\n" "#define int32_t $ac_cv_c_int32_t" >>confdefs.h ;; esac ac_fn_c_find_intX_t "$LINENO" "64" "ac_cv_c_int64_t" case $ac_cv_c_int64_t in #( no|yes) ;; #( *) printf "%s\n" "#define int64_t $ac_cv_c_int64_t" >>confdefs.h ;; esac ac_fn_c_check_type "$LINENO" "mode_t" "ac_cv_type_mode_t" "$ac_includes_default" if test "x$ac_cv_type_mode_t" = xyes then : else $as_nop printf "%s\n" "#define mode_t int" >>confdefs.h fi ac_fn_c_check_type "$LINENO" "off_t" "ac_cv_type_off_t" "$ac_includes_default" if test "x$ac_cv_type_off_t" = xyes then : else $as_nop printf "%s\n" "#define off_t long int" >>confdefs.h fi ac_fn_c_check_type "$LINENO" "size_t" "ac_cv_type_size_t" "$ac_includes_default" if test "x$ac_cv_type_size_t" = xyes then : else $as_nop printf "%s\n" "#define size_t unsigned int" >>confdefs.h fi ac_fn_c_check_type "$LINENO" "ssize_t" "ac_cv_type_ssize_t" "$ac_includes_default" if test "x$ac_cv_type_ssize_t" = xyes then : else $as_nop printf "%s\n" "#define ssize_t int" >>confdefs.h fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 printf %s "checking how to run the C preprocessor... " >&6; } # On Suns, sometimes $CPP names a directory. if test -n "$CPP" && test -d "$CPP"; then CPP= fi if test -z "$CPP"; then if test ${ac_cv_prog_CPP+y} then : printf %s "(cached) " >&6 else $as_nop # Double quotes because $CC needs to be expanded for CPP in "$CC -E" "$CC -E -traditional-cpp" cpp /lib/cpp do ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO" then : else $as_nop # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO" then : # Broken: success on invalid input. continue else $as_nop # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok then : break fi done ac_cv_prog_CPP=$CPP fi CPP=$ac_cv_prog_CPP else ac_cv_prog_CPP=$CPP fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 printf "%s\n" "$CPP" >&6; } ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO" then : else $as_nop # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO" then : # Broken: success on invalid input. continue else $as_nop # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok then : else $as_nop { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "C preprocessor \"$CPP\" fails sanity check See \`config.log' for more details" "$LINENO" 5; } fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 printf %s "checking for grep that handles long lines and -e... " >&6; } if test ${ac_cv_path_GREP+y} then : printf %s "(cached) " >&6 else $as_nop if test -z "$GREP"; then ac_path_GREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_prog in grep ggrep do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_GREP="$as_dir$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_GREP" || continue # Check for GNU ac_path_GREP and select it if it is found. # Check for GNU $ac_path_GREP case `"$ac_path_GREP" --version 2>&1` in *GNU*) ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; *) ac_count=0 printf %s 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" printf "%s\n" 'GREP' >> "conftest.nl" "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_GREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_GREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_GREP"; then as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_GREP=$GREP fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 printf "%s\n" "$ac_cv_path_GREP" >&6; } GREP="$ac_cv_path_GREP" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 printf %s "checking for egrep... " >&6; } if test ${ac_cv_path_EGREP+y} then : printf %s "(cached) " >&6 else $as_nop if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 then ac_cv_path_EGREP="$GREP -E" else if test -z "$EGREP"; then ac_path_EGREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_prog in egrep do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_EGREP="$as_dir$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_EGREP" || continue # Check for GNU ac_path_EGREP and select it if it is found. # Check for GNU $ac_path_EGREP case `"$ac_path_EGREP" --version 2>&1` in *GNU*) ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; *) ac_count=0 printf %s 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" printf "%s\n" 'EGREP' >> "conftest.nl" "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_EGREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_EGREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_EGREP"; then as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_EGREP=$EGREP fi fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 printf "%s\n" "$ac_cv_path_EGREP" >&6; } EGREP="$ac_cv_path_EGREP" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for uid_t in sys/types.h" >&5 printf %s "checking for uid_t in sys/types.h... " >&6; } if test ${ac_cv_type_uid_t+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "uid_t" >/dev/null 2>&1 then : ac_cv_type_uid_t=yes else $as_nop ac_cv_type_uid_t=no fi rm -rf conftest* fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_uid_t" >&5 printf "%s\n" "$ac_cv_type_uid_t" >&6; } if test $ac_cv_type_uid_t = no; then printf "%s\n" "#define uid_t int" >>confdefs.h printf "%s\n" "#define gid_t int" >>confdefs.h fi ac_fn_c_find_uintX_t "$LINENO" "8" "ac_cv_c_uint8_t" case $ac_cv_c_uint8_t in #( no|yes) ;; #( *) printf "%s\n" "#define _UINT8_T 1" >>confdefs.h printf "%s\n" "#define uint8_t $ac_cv_c_uint8_t" >>confdefs.h ;; esac ac_fn_c_find_uintX_t "$LINENO" "16" "ac_cv_c_uint16_t" case $ac_cv_c_uint16_t in #( no|yes) ;; #( *) printf "%s\n" "#define uint16_t $ac_cv_c_uint16_t" >>confdefs.h ;; esac ac_fn_c_find_uintX_t "$LINENO" "32" "ac_cv_c_uint32_t" case $ac_cv_c_uint32_t in #( no|yes) ;; #( *) printf "%s\n" "#define _UINT32_T 1" >>confdefs.h printf "%s\n" "#define uint32_t $ac_cv_c_uint32_t" >>confdefs.h ;; esac ac_fn_c_find_uintX_t "$LINENO" "64" "ac_cv_c_uint64_t" case $ac_cv_c_uint64_t in #( no|yes) ;; #( *) printf "%s\n" "#define _UINT64_T 1" >>confdefs.h printf "%s\n" "#define uint64_t $ac_cv_c_uint64_t" >>confdefs.h ;; esac ac_fn_c_check_type "$LINENO" "ptrdiff_t" "ac_cv_type_ptrdiff_t" "$ac_includes_default" if test "x$ac_cv_type_ptrdiff_t" = xyes then : printf "%s\n" "#define HAVE_PTRDIFF_T 1" >>confdefs.h fi # Checks for library functions. # Make sure we can run config.sub. $SHELL "${ac_aux_dir}config.sub" sun4 >/dev/null 2>&1 || as_fn_error $? "cannot run $SHELL ${ac_aux_dir}config.sub" "$LINENO" 5 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking build system type" >&5 printf %s "checking build system type... " >&6; } if test ${ac_cv_build+y} then : printf %s "(cached) " >&6 else $as_nop ac_build_alias=$build_alias test "x$ac_build_alias" = x && ac_build_alias=`$SHELL "${ac_aux_dir}config.guess"` test "x$ac_build_alias" = x && as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5 ac_cv_build=`$SHELL "${ac_aux_dir}config.sub" $ac_build_alias` || as_fn_error $? "$SHELL ${ac_aux_dir}config.sub $ac_build_alias failed" "$LINENO" 5 fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5 printf "%s\n" "$ac_cv_build" >&6; } case $ac_cv_build in *-*-*) ;; *) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;; esac build=$ac_cv_build ac_save_IFS=$IFS; IFS='-' set x $ac_cv_build shift build_cpu=$1 build_vendor=$2 shift; shift # Remember, the first character of IFS is used to create $*, # except with old shells: build_os=$* IFS=$ac_save_IFS case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking host system type" >&5 printf %s "checking host system type... " >&6; } if test ${ac_cv_host+y} then : printf %s "(cached) " >&6 else $as_nop if test "x$host_alias" = x; then ac_cv_host=$ac_cv_build else ac_cv_host=`$SHELL "${ac_aux_dir}config.sub" $host_alias` || as_fn_error $? "$SHELL ${ac_aux_dir}config.sub $host_alias failed" "$LINENO" 5 fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5 printf "%s\n" "$ac_cv_host" >&6; } case $ac_cv_host in *-*-*) ;; *) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;; esac host=$ac_cv_host ac_save_IFS=$IFS; IFS='-' set x $ac_cv_host shift host_cpu=$1 host_vendor=$2 shift; shift # Remember, the first character of IFS is used to create $*, # except with old shells: host_os=$* IFS=$ac_save_IFS case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for working chown" >&5 printf %s "checking for working chown... " >&6; } if test ${ac_cv_func_chown_works+y} then : printf %s "(cached) " >&6 else $as_nop if test "$cross_compiling" = yes then : case "$host_os" in # (( # Guess yes on glibc systems. *-gnu*) ac_cv_func_chown_works=yes ;; # If we don't know, assume the worst. *) ac_cv_func_chown_works=no ;; esac else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default #include int main (void) { char *f = "conftest.chown"; struct stat before, after; if (creat (f, 0600) < 0) return 1; if (stat (f, &before) < 0) return 1; if (chown (f, (uid_t) -1, (gid_t) -1) == -1) return 1; if (stat (f, &after) < 0) return 1; return ! (before.st_uid == after.st_uid && before.st_gid == after.st_gid); ; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO" then : ac_cv_func_chown_works=yes else $as_nop ac_cv_func_chown_works=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi rm -f conftest.chown fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_chown_works" >&5 printf "%s\n" "$ac_cv_func_chown_works" >&6; } if test $ac_cv_func_chown_works = yes; then printf "%s\n" "#define HAVE_CHOWN 1" >>confdefs.h fi ac_func= for ac_item in $ac_func_c_list do if test $ac_func; then ac_fn_c_check_func "$LINENO" $ac_func ac_cv_func_$ac_func if eval test \"x\$ac_cv_func_$ac_func\" = xyes; then echo "#define $ac_item 1" >> confdefs.h fi ac_func= else ac_func=$ac_item fi done { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for working mmap" >&5 printf %s "checking for working mmap... " >&6; } if test ${ac_cv_func_mmap_fixed_mapped+y} then : printf %s "(cached) " >&6 else $as_nop if test "$cross_compiling" = yes then : case "$host_os" in # (( # Guess yes on platforms where we know the result. linux*) ac_cv_func_mmap_fixed_mapped=yes ;; # If we don't know, assume the worst. *) ac_cv_func_mmap_fixed_mapped=no ;; esac else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default /* malloc might have been renamed as rpl_malloc. */ #undef malloc /* Thanks to Mike Haertel and Jim Avera for this test. Here is a matrix of mmap possibilities: mmap private not fixed mmap private fixed at somewhere currently unmapped mmap private fixed at somewhere already mapped mmap shared not fixed mmap shared fixed at somewhere currently unmapped mmap shared fixed at somewhere already mapped For private mappings, we should verify that changes cannot be read() back from the file, nor mmap's back from the file at a different address. (There have been systems where private was not correctly implemented like the infamous i386 svr4.0, and systems where the VM page cache was not coherent with the file system buffer cache like early versions of FreeBSD and possibly contemporary NetBSD.) For shared mappings, we should conversely verify that changes get propagated back to all the places they're supposed to be. Grep wants private fixed already mapped. The main things grep needs to know about mmap are: * does it exist and is it safe to write into the mmap'd area * how to use it (BSD variants) */ #include #include /* This mess was copied from the GNU getpagesize.h. */ #ifndef HAVE_GETPAGESIZE # ifdef _SC_PAGESIZE # define getpagesize() sysconf(_SC_PAGESIZE) # else /* no _SC_PAGESIZE */ # ifdef HAVE_SYS_PARAM_H # include # ifdef EXEC_PAGESIZE # define getpagesize() EXEC_PAGESIZE # else /* no EXEC_PAGESIZE */ # ifdef NBPG # define getpagesize() NBPG * CLSIZE # ifndef CLSIZE # define CLSIZE 1 # endif /* no CLSIZE */ # else /* no NBPG */ # ifdef NBPC # define getpagesize() NBPC # else /* no NBPC */ # ifdef PAGESIZE # define getpagesize() PAGESIZE # endif /* PAGESIZE */ # endif /* no NBPC */ # endif /* no NBPG */ # endif /* no EXEC_PAGESIZE */ # else /* no HAVE_SYS_PARAM_H */ # define getpagesize() 8192 /* punt totally */ # endif /* no HAVE_SYS_PARAM_H */ # endif /* no _SC_PAGESIZE */ #endif /* no HAVE_GETPAGESIZE */ int main (void) { char *data, *data2, *data3; const char *cdata2; int i, pagesize; int fd, fd2; pagesize = getpagesize (); /* First, make a file with some known garbage in it. */ data = (char *) malloc (pagesize); if (!data) return 1; for (i = 0; i < pagesize; ++i) *(data + i) = rand (); umask (0); fd = creat ("conftest.mmap", 0600); if (fd < 0) return 2; if (write (fd, data, pagesize) != pagesize) return 3; close (fd); /* Next, check that the tail of a page is zero-filled. File must have non-zero length, otherwise we risk SIGBUS for entire page. */ fd2 = open ("conftest.txt", O_RDWR | O_CREAT | O_TRUNC, 0600); if (fd2 < 0) return 4; cdata2 = ""; if (write (fd2, cdata2, 1) != 1) return 5; data2 = (char *) mmap (0, pagesize, PROT_READ | PROT_WRITE, MAP_SHARED, fd2, 0L); if (data2 == MAP_FAILED) return 6; for (i = 0; i < pagesize; ++i) if (*(data2 + i)) return 7; close (fd2); if (munmap (data2, pagesize)) return 8; /* Next, try to mmap the file at a fixed address which already has something else allocated at it. If we can, also make sure that we see the same garbage. */ fd = open ("conftest.mmap", O_RDWR); if (fd < 0) return 9; if (data2 != mmap (data2, pagesize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_FIXED, fd, 0L)) return 10; for (i = 0; i < pagesize; ++i) if (*(data + i) != *(data2 + i)) return 11; /* Finally, make sure that changes to the mapped area do not percolate back to the file as seen by read(). (This is a bug on some variants of i386 svr4.0.) */ for (i = 0; i < pagesize; ++i) *(data2 + i) = *(data2 + i) + 1; data3 = (char *) malloc (pagesize); if (!data3) return 12; if (read (fd, data3, pagesize) != pagesize) return 13; for (i = 0; i < pagesize; ++i) if (*(data + i) != *(data3 + i)) return 14; close (fd); free (data); free (data3); return 0; } _ACEOF if ac_fn_c_try_run "$LINENO" then : ac_cv_func_mmap_fixed_mapped=yes else $as_nop ac_cv_func_mmap_fixed_mapped=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_mmap_fixed_mapped" >&5 printf "%s\n" "$ac_cv_func_mmap_fixed_mapped" >&6; } if test $ac_cv_func_mmap_fixed_mapped = yes; then printf "%s\n" "#define HAVE_MMAP 1" >>confdefs.h fi rm -f conftest.mmap conftest.txt { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether lstat correctly handles trailing slash" >&5 printf %s "checking whether lstat correctly handles trailing slash... " >&6; } if test ${ac_cv_func_lstat_dereferences_slashed_symlink+y} then : printf %s "(cached) " >&6 else $as_nop rm -f conftest.sym conftest.file echo >conftest.file if test "$as_ln_s" = "ln -s" && ln -s conftest.file conftest.sym; then if test "$cross_compiling" = yes then : case "$host_os" in # (( # Guess yes on glibc systems. *-gnu*) ac_cv_func_lstat_dereferences_slashed_symlink=yes ;; # If we don't know, assume the worst. *) ac_cv_func_lstat_dereferences_slashed_symlink=no ;; esac else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default int main (void) { struct stat sbuf; /* Linux will dereference the symlink and fail, as required by POSIX. That is better in the sense that it means we will not have to compile and use the lstat wrapper. */ return lstat ("conftest.sym/", &sbuf) == 0; ; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO" then : ac_cv_func_lstat_dereferences_slashed_symlink=yes else $as_nop ac_cv_func_lstat_dereferences_slashed_symlink=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi else # If the `ln -s' command failed, then we probably don't even # have an lstat function. ac_cv_func_lstat_dereferences_slashed_symlink=no fi rm -f conftest.sym conftest.file fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_lstat_dereferences_slashed_symlink" >&5 printf "%s\n" "$ac_cv_func_lstat_dereferences_slashed_symlink" >&6; } test $ac_cv_func_lstat_dereferences_slashed_symlink = yes && printf "%s\n" "#define LSTAT_FOLLOWS_SLASHED_SYMLINK 1" >>confdefs.h if test "x$ac_cv_func_lstat_dereferences_slashed_symlink" = xno; then case " $LIBOBJS " in *" lstat.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS lstat.$ac_objext" ;; esac fi ac_fn_c_check_func "$LINENO" "arc4random_uniform" "ac_cv_func_arc4random_uniform" if test "x$ac_cv_func_arc4random_uniform" = xyes then : printf "%s\n" "#define HAVE_ARC4RANDOM_UNIFORM 1" >>confdefs.h fi for ac_func in clock_gettime ftruncate getpagesize memset mkdir munmap pathconf realpath socket strdup strndup strerror strtoull do : as_ac_var=`printf "%s\n" "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" if eval test \"x\$"$as_ac_var"\" = x"yes" then : cat >>confdefs.h <<_ACEOF #define `printf "%s\n" "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF else $as_nop as_fn_error $? "required function missing" "$LINENO" 5 fi done ac_fn_c_check_func "$LINENO" "epoll_create1" "ac_cv_func_epoll_create1" if test "x$ac_cv_func_epoll_create1" = xyes then : printf "%s\n" "#define HAVE_EPOLL_CREATE1 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "kqueue" "ac_cv_func_kqueue" if test "x$ac_cv_func_kqueue" = xyes then : printf "%s\n" "#define HAVE_KQUEUE 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "poll" "ac_cv_func_poll" if test "x$ac_cv_func_poll" = xyes then : printf "%s\n" "#define HAVE_POLL 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "recvmmsg" "ac_cv_func_recvmmsg" if test "x$ac_cv_func_recvmmsg" = xyes then : printf "%s\n" "#define HAVE_RECVMMSG 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "utimensat" "ac_cv_func_utimensat" if test "x$ac_cv_func_utimensat" = xyes then : printf "%s\n" "#define HAVE_UTIMENSAT 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "utimes" "ac_cv_func_utimes" if test "x$ac_cv_func_utimes" = xyes then : printf "%s\n" "#define HAVE_UTIMES 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "recvmmsg" "ac_cv_func_recvmmsg" if test "x$ac_cv_func_recvmmsg" = xyes then : printf "%s\n" "#define HAVE_RECVMMSG 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "rawmemchr" "ac_cv_func_rawmemchr" if test "x$ac_cv_func_rawmemchr" = xyes then : printf "%s\n" "#define HAVE_RAWMEMCHR 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "memchr" "ac_cv_func_memchr" if test "x$ac_cv_func_memchr" = xyes then : printf "%s\n" "#define HAVE_MEMCHR 1" >>confdefs.h fi for ac_func in getcwd do : ac_fn_c_check_func "$LINENO" "getcwd" "ac_cv_func_getcwd" if test "x$ac_cv_func_getcwd" = xyes then : printf "%s\n" "#define HAVE_GETCWD 1" >>confdefs.h else $as_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: required test function missing. Some tests may not function" >&5 printf "%s\n" "$as_me: WARNING: required test function missing. Some tests may not function" >&2;} fi done ac_config_files="$ac_config_files Makefile doc/Makefile libs/Makefile libs/blake3/Makefile libs/blake3/c/Makefile src/Makefile test/Makefile examples/Makefile include/librecast/crypto.h include/librecast/types.h" if test "x$with_mld" != "xno"; then subdirs="$subdirs libs/libmld" fi cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure # tests run on this system so they can be shared between configure # scripts and configure runs, see configure's option --config-cache. # It is not useful on other systems. If it contains results you don't # want to keep, you may remove or edit it. # # config.status only pays attention to the cache file if you give it # the --recheck option to rerun configure. # # `ac_cv_env_foo' variables (set or unset) will be overridden when # loading this file, other *unset* `ac_cv_foo' will be assigned the # following values. _ACEOF # The following way of writing the cache mishandles newlines in values, # but we know of no workaround that is simple, portable, and efficient. # So, we kill variables containing newlines. # Ultrix sh set writes to stderr and can't be redirected directly, # and sets the high bit in the cache file unless we assign to the vars. ( for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 printf "%s\n" "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space=' '; set) 2>&1` in #( *${as_nl}ac_space=\ *) # `set' does not quote correctly, so add quotes: double-quote # substitution turns \\\\ into \\, and sed turns \\ into \. sed -n \ "s/'/'\\\\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" ;; #( *) # `set' quotes correctly as required by POSIX, so do not add quotes. sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) | sed ' /^ac_cv_env_/b end t clear :clear s/^\([^=]*\)=\(.*[{}].*\)$/test ${\1+y} || &/ t end s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ :end' >>confcache if diff "$cache_file" confcache >/dev/null 2>&1; then :; else if test -w "$cache_file"; then if test "x$cache_file" != "x/dev/null"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 printf "%s\n" "$as_me: updating cache $cache_file" >&6;} if test ! -f "$cache_file" || test -h "$cache_file"; then cat confcache >"$cache_file" else case $cache_file in #( */* | ?:*) mv -f confcache "$cache_file"$$ && mv -f "$cache_file"$$ "$cache_file" ;; #( *) mv -f confcache "$cache_file" ;; esac fi fi else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 printf "%s\n" "$as_me: not updating unwritable cache $cache_file" >&6;} fi fi rm -f confcache test "x$prefix" = xNONE && prefix=$ac_default_prefix # Let make expand exec_prefix. test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' DEFS=-DHAVE_CONFIG_H ac_libobjs= ac_ltlibobjs= U= for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue # 1. Remove the extension, and $U if already installed. ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' ac_i=`printf "%s\n" "$ac_i" | sed "$ac_script"` # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR # will be set to the directory where LIBOBJS objects are built. as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' done LIBOBJS=$ac_libobjs LTLIBOBJS=$ac_ltlibobjs : "${CONFIG_STATUS=./config.status}" ac_write_fail=0 ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files $CONFIG_STATUS" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 printf "%s\n" "$as_me: creating $CONFIG_STATUS" >&6;} as_write_fail=0 cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 #! $SHELL # Generated by $as_me. # Run this file to recreate the current configuration. # Compiler output produced by configure, useful for debugging # configure, is in config.log if it exists. debug=false ac_cs_recheck=false ac_cs_silent=false SHELL=\${CONFIG_SHELL-$SHELL} export SHELL _ASEOF cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh as_nop=: if test ${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else $as_nop case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi # Reset variables that may have inherited troublesome values from # the environment. # IFS needs to be set, to space, tab, and newline, in precisely that order. # (If _AS_PATH_WALK were called with IFS unset, it would have the # side effect of setting IFS to empty, thus disabling word splitting.) # Quoting is to prevent editors from complaining about space-tab. as_nl=' ' export as_nl IFS=" "" $as_nl" PS1='$ ' PS2='> ' PS4='+ ' # Ensure predictable behavior from utilities with locale-dependent output. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # We cannot yet rely on "unset" to work, but we need these variables # to be unset--not just set to an empty or harmless value--now, to # avoid bugs in old shells (e.g. pre-3.0 UWIN ksh). This construct # also avoids known problems related to "unset" and subshell syntax # in other old shells (e.g. bash 2.01 and pdksh 5.2.14). for as_var in BASH_ENV ENV MAIL MAILPATH CDPATH do eval test \${$as_var+y} \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done # Ensure that fds 0, 1, and 2 are open. if (exec 3>&0) 2>/dev/null; then :; else exec 0&1) 2>/dev/null; then :; else exec 1>/dev/null; fi if (exec 3>&2) ; then :; else exec 2>/dev/null; fi # The user is always right. if ${PATH_SEPARATOR+false} :; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac test -r "$as_dir$0" && as_myself=$as_dir$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then printf "%s\n" "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi printf "%s\n" "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null then : eval 'as_fn_append () { eval $1+=\$2 }' else $as_nop as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null then : eval 'as_fn_arith () { as_val=$(( $* )) }' else $as_nop as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || printf "%s\n" X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits # Determine whether it's possible to make 'echo' print without a newline. # These variables are no longer used directly by Autoconf, but are AC_SUBSTed # for compatibility with existing Makefiles. ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac # For backward compatibility with old third-party macros, we provide # the shell variables $as_echo and $as_echo_n. New code should use # AS_ECHO(["message"]) and AS_ECHO_N(["message"]), respectively. as_echo='printf %s\n' as_echo_n='printf %s' rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -pR' fi else as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`printf "%s\n" "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || printf "%s\n" X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi # as_fn_executable_p FILE # ----------------------- # Test if FILE is an executable regular file. as_fn_executable_p () { test -f "$1" && test -x "$1" } # as_fn_executable_p as_test_x='test -x' as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" exec 6>&1 ## ----------------------------------- ## ## Main body of $CONFIG_STATUS script. ## ## ----------------------------------- ## _ASEOF test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Save the log message, to keep $0 and so on meaningful, and to # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" This file was extended by librecast $as_me 0.11.2, which was generated by GNU Autoconf 2.71. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS CONFIG_LINKS = $CONFIG_LINKS CONFIG_COMMANDS = $CONFIG_COMMANDS $ $0 $@ on `(hostname || uname -n) 2>/dev/null | sed 1q` " _ACEOF case $ac_config_files in *" "*) set x $ac_config_files; shift; ac_config_files=$*;; esac case $ac_config_headers in *" "*) set x $ac_config_headers; shift; ac_config_headers=$*;; esac cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # Files that config.status was made for. config_files="$ac_config_files" config_headers="$ac_config_headers" _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 ac_cs_usage="\ \`$as_me' instantiates files and other configuration actions from templates according to the current configuration. Unless the files and actions are specified as TAGs, all are instantiated by default. Usage: $0 [OPTION]... [TAG]... -h, --help print this help, then exit -V, --version print version number and configuration settings, then exit --config print configuration, then exit -q, --quiet, --silent do not print progress messages -d, --debug don't remove temporary files --recheck update $as_me by reconfiguring in the same conditions --file=FILE[:TEMPLATE] instantiate the configuration file FILE --header=FILE[:TEMPLATE] instantiate the configuration header FILE Configuration files: $config_files Configuration headers: $config_headers Report bugs to ." _ACEOF ac_cs_config=`printf "%s\n" "$ac_configure_args" | sed "$ac_safe_unquote"` ac_cs_config_escaped=`printf "%s\n" "$ac_cs_config" | sed "s/^ //; s/'/'\\\\\\\\''/g"` cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config='$ac_cs_config_escaped' ac_cs_version="\\ librecast config.status 0.11.2 configured by $0, generated by GNU Autoconf 2.71, with options \\"\$ac_cs_config\\" Copyright (C) 2021 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." ac_pwd='$ac_pwd' srcdir='$srcdir' INSTALL='$INSTALL' test -n "\$AWK" || AWK=awk _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # The default lists apply if the user does not specify any file. ac_need_defaults=: while test $# != 0 do case $1 in --*=?*) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` ac_shift=: ;; --*=) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg= ac_shift=: ;; *) ac_option=$1 ac_optarg=$2 ac_shift=shift ;; esac case $ac_option in # Handling of the options. -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) ac_cs_recheck=: ;; --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) printf "%s\n" "$ac_cs_version"; exit ;; --config | --confi | --conf | --con | --co | --c ) printf "%s\n" "$ac_cs_config"; exit ;; --debug | --debu | --deb | --de | --d | -d ) debug=: ;; --file | --fil | --fi | --f ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`printf "%s\n" "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; '') as_fn_error $? "missing file argument" ;; esac as_fn_append CONFIG_FILES " '$ac_optarg'" ac_need_defaults=false;; --header | --heade | --head | --hea ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`printf "%s\n" "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; esac as_fn_append CONFIG_HEADERS " '$ac_optarg'" ac_need_defaults=false;; --he | --h) # Conflict between --help and --header as_fn_error $? "ambiguous option: \`$1' Try \`$0 --help' for more information.";; --help | --hel | -h ) printf "%s\n" "$ac_cs_usage"; exit ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil | --si | --s) ac_cs_silent=: ;; # This is an error. -*) as_fn_error $? "unrecognized option: \`$1' Try \`$0 --help' for more information." ;; *) as_fn_append ac_config_targets " $1" ac_need_defaults=false ;; esac shift done ac_configure_extra_args= if $ac_cs_silent; then exec 6>/dev/null ac_configure_extra_args="$ac_configure_extra_args --silent" fi _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 if \$ac_cs_recheck; then set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion shift \printf "%s\n" "running CONFIG_SHELL=$SHELL \$*" >&6 CONFIG_SHELL='$SHELL' export CONFIG_SHELL exec "\$@" fi _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 exec 5>>config.log { echo sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX ## Running $as_me. ## _ASBOX printf "%s\n" "$ac_log" } >&5 _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Handling of arguments. for ac_config_target in $ac_config_targets do case $ac_config_target in "src/config.h") CONFIG_HEADERS="$CONFIG_HEADERS src/config.h" ;; "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; "doc/Makefile") CONFIG_FILES="$CONFIG_FILES doc/Makefile" ;; "libs/Makefile") CONFIG_FILES="$CONFIG_FILES libs/Makefile" ;; "libs/blake3/Makefile") CONFIG_FILES="$CONFIG_FILES libs/blake3/Makefile" ;; "libs/blake3/c/Makefile") CONFIG_FILES="$CONFIG_FILES libs/blake3/c/Makefile" ;; "src/Makefile") CONFIG_FILES="$CONFIG_FILES src/Makefile" ;; "test/Makefile") CONFIG_FILES="$CONFIG_FILES test/Makefile" ;; "examples/Makefile") CONFIG_FILES="$CONFIG_FILES examples/Makefile" ;; "include/librecast/crypto.h") CONFIG_FILES="$CONFIG_FILES include/librecast/crypto.h" ;; "include/librecast/types.h") CONFIG_FILES="$CONFIG_FILES include/librecast/types.h" ;; *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; esac done # If the user did not use the arguments to specify the items to instantiate, # then the envvar interface is used. Set only those that are not. # We use the long form for the default assignment because of an extremely # bizarre bug on SunOS 4.1.3. if $ac_need_defaults; then test ${CONFIG_FILES+y} || CONFIG_FILES=$config_files test ${CONFIG_HEADERS+y} || CONFIG_HEADERS=$config_headers fi # Have a temporary directory for convenience. Make it in the build tree # simply because there is no reason against having it here, and in addition, # creating and moving files from /tmp can sometimes cause problems. # Hook for its removal unless debugging. # Note that there is a small window in which the directory will not be cleaned: # after its creation but before its name has been assigned to `$tmp'. $debug || { tmp= ac_tmp= trap 'exit_status=$? : "${ac_tmp:=$tmp}" { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status ' 0 trap 'as_fn_exit 1' 1 2 13 15 } # Create a (secure) tmp directory for tmp files. { tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && test -d "$tmp" } || { tmp=./conf$$-$RANDOM (umask 077 && mkdir "$tmp") } || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 ac_tmp=$tmp # Set up the scripts for CONFIG_FILES section. # No need to generate them if there are no CONFIG_FILES. # This happens for instance with `./config.status config.h'. if test -n "$CONFIG_FILES"; then ac_cr=`echo X | tr X '\015'` # On cygwin, bash can eat \r inside `` if the user requested igncr. # But we know of no other shell where ac_cr would be empty at this # point, so we can use a bashism as a fallback. if test "x$ac_cr" = x; then eval ac_cr=\$\'\\r\' fi ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then ac_cs_awk_cr='\\r' else ac_cs_awk_cr=$ac_cr fi echo 'BEGIN {' >"$ac_tmp/subs1.awk" && _ACEOF { echo "cat >conf$$subs.awk <<_ACEOF" && echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && echo "_ACEOF" } >conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` ac_delim='%!_!# ' for ac_last_try in false false false false false :; do . ./conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` if test $ac_delim_n = $ac_delim_num; then break elif $ac_last_try; then as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done rm -f conf$$subs.sh cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK && _ACEOF sed -n ' h s/^/S["/; s/!.*/"]=/ p g s/^[^!]*!// :repl t repl s/'"$ac_delim"'$// t delim :nl h s/\(.\{148\}\)..*/\1/ t more1 s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ p n b repl :more1 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t nl :delim h s/\(.\{148\}\)..*/\1/ t more2 s/["\\]/\\&/g; s/^/"/; s/$/"/ p b :more2 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t delim ' >$CONFIG_STATUS || ac_write_fail=1 rm -f conf$$subs.awk cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACAWK cat >>"\$ac_tmp/subs1.awk" <<_ACAWK && for (key in S) S_is_set[key] = 1 FS = "" } { line = $ 0 nfields = split(line, field, "@") substed = 0 len = length(field[1]) for (i = 2; i < nfields; i++) { key = field[i] keylen = length(key) if (S_is_set[key]) { value = S[key] line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) len += length(value) + length(field[++i]) substed = 1 } else len += 1 + keylen } print line } _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" else cat fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 _ACEOF # VPATH may cause trouble with some makes, so we remove sole $(srcdir), # ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and # trailing colons and then remove the whole line if VPATH becomes empty # (actually we leave an empty line to preserve line numbers). if test "x$srcdir" = x.; then ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ h s/// s/^/:/ s/[ ]*$/:/ s/:\$(srcdir):/:/g s/:\${srcdir}:/:/g s/:@srcdir@:/:/g s/^:*// s/:*$// x s/\(=[ ]*\).*/\1/ G s/\n// s/^[^=]*=[ ]*$// }' fi cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 fi # test -n "$CONFIG_FILES" # Set up the scripts for CONFIG_HEADERS section. # No need to generate them if there are no CONFIG_HEADERS. # This happens for instance with `./config.status Makefile'. if test -n "$CONFIG_HEADERS"; then cat >"$ac_tmp/defines.awk" <<\_ACAWK || BEGIN { _ACEOF # Transform confdefs.h into an awk script `defines.awk', embedded as # here-document in config.status, that substitutes the proper values into # config.h.in to produce config.h. # Create a delimiter string that does not exist in confdefs.h, to ease # handling of long lines. ac_delim='%!_!# ' for ac_last_try in false false :; do ac_tt=`sed -n "/$ac_delim/p" confdefs.h` if test -z "$ac_tt"; then break elif $ac_last_try; then as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done # For the awk script, D is an array of macro values keyed by name, # likewise P contains macro parameters if any. Preserve backslash # newline sequences. ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]* sed -n ' s/.\{148\}/&'"$ac_delim"'/g t rset :rset s/^[ ]*#[ ]*define[ ][ ]*/ / t def d :def s/\\$// t bsnl s/["\\]/\\&/g s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ D["\1"]=" \3"/p s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2"/p d :bsnl s/["\\]/\\&/g s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ D["\1"]=" \3\\\\\\n"\\/p t cont s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p t cont d :cont n s/.\{148\}/&'"$ac_delim"'/g t clear :clear s/\\$// t bsnlc s/["\\]/\\&/g; s/^/"/; s/$/"/p d :bsnlc s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p b cont ' >$CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 for (key in D) D_is_set[key] = 1 FS = "" } /^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ { line = \$ 0 split(line, arg, " ") if (arg[1] == "#") { defundef = arg[2] mac1 = arg[3] } else { defundef = substr(arg[1], 2) mac1 = arg[2] } split(mac1, mac2, "(") #) macro = mac2[1] prefix = substr(line, 1, index(line, defundef) - 1) if (D_is_set[macro]) { # Preserve the white space surrounding the "#". print prefix "define", macro P[macro] D[macro] next } else { # Replace #undef with comments. This is necessary, for example, # in the case of _POSIX_SOURCE, which is predefined and required # on some systems where configure will not decide to define it. if (defundef == "undef") { print "/*", prefix defundef, macro, "*/" next } } } { print } _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 as_fn_error $? "could not setup config headers machinery" "$LINENO" 5 fi # test -n "$CONFIG_HEADERS" eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS " shift for ac_tag do case $ac_tag in :[FHLC]) ac_mode=$ac_tag; continue;; esac case $ac_mode$ac_tag in :[FHL]*:*);; :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; :[FH]-) ac_tag=-:-;; :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; esac ac_save_IFS=$IFS IFS=: set x $ac_tag IFS=$ac_save_IFS shift ac_file=$1 shift case $ac_mode in :L) ac_source=$1;; :[FH]) ac_file_inputs= for ac_f do case $ac_f in -) ac_f="$ac_tmp/stdin";; *) # Look for the file first in the build tree, then in the source tree # (if the path is not absolute). The absolute path cannot be DOS-style, # because $ac_f cannot contain `:'. test -f "$ac_f" || case $ac_f in [\\/$]*) false;; *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; esac || as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; esac case $ac_f in *\'*) ac_f=`printf "%s\n" "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac as_fn_append ac_file_inputs " '$ac_f'" done # Let's still pretend it is `configure' which instantiates (i.e., don't # use $as_me), people would be surprised to read: # /* config.h. Generated by config.status. */ configure_input='Generated from '` printf "%s\n" "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' `' by configure.' if test x"$ac_file" != x-; then configure_input="$ac_file. $configure_input" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 printf "%s\n" "$as_me: creating $ac_file" >&6;} fi # Neutralize special characters interpreted by sed in replacement strings. case $configure_input in #( *\&* | *\|* | *\\* ) ac_sed_conf_input=`printf "%s\n" "$configure_input" | sed 's/[\\\\&|]/\\\\&/g'`;; #( *) ac_sed_conf_input=$configure_input;; esac case $ac_tag in *:-:* | *:-) cat >"$ac_tmp/stdin" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; esac ;; esac ac_dir=`$as_dirname -- "$ac_file" || $as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$ac_file" : 'X\(//\)[^/]' \| \ X"$ac_file" : 'X\(//\)$' \| \ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || printf "%s\n" X"$ac_file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` as_dir="$ac_dir"; as_fn_mkdir_p ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`printf "%s\n" "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`printf "%s\n" "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix case $ac_mode in :F) # # CONFIG_FILE # case $INSTALL in [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; esac _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # If the template does not know about datarootdir, expand it. # FIXME: This hack should be removed a few years after 2.60. ac_datarootdir_hack=; ac_datarootdir_seen= ac_sed_dataroot=' /datarootdir/ { p q } /@datadir@/p /@docdir@/p /@infodir@/p /@localedir@/p /@mandir@/p' case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in *datarootdir*) ac_datarootdir_seen=yes;; *@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 printf "%s\n" "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_datarootdir_hack=' s&@datadir@&$datadir&g s&@docdir@&$docdir&g s&@infodir@&$infodir&g s&@localedir@&$localedir&g s&@mandir@&$mandir&g s&\\\${datarootdir}&$datarootdir&g' ;; esac _ACEOF # Neutralize VPATH when `$srcdir' = `.'. # Shell code in configure.ac might set extrasub. # FIXME: do we really want to maintain this feature? cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_sed_extra="$ac_vpsub $extrasub _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 :t /@[a-zA-Z_][a-zA-Z_0-9]*@/!b s|@configure_input@|$ac_sed_conf_input|;t t s&@top_builddir@&$ac_top_builddir_sub&;t t s&@top_build_prefix@&$ac_top_build_prefix&;t t s&@srcdir@&$ac_srcdir&;t t s&@abs_srcdir@&$ac_abs_srcdir&;t t s&@top_srcdir@&$ac_top_srcdir&;t t s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t s&@builddir@&$ac_builddir&;t t s&@abs_builddir@&$ac_abs_builddir&;t t s&@abs_top_builddir@&$ac_abs_top_builddir&;t t s&@INSTALL@&$ac_INSTALL&;t t $ac_datarootdir_hack " eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ "$ac_tmp/out"`; test -z "$ac_out"; } && { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&5 printf "%s\n" "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&2;} rm -f "$ac_tmp/stdin" case $ac_file in -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; esac \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; :H) # # CONFIG_HEADER # if test x"$ac_file" != x-; then { printf "%s\n" "/* $configure_input */" >&1 \ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" } >"$ac_tmp/config.h" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 printf "%s\n" "$as_me: $ac_file is unchanged" >&6;} else rm -f "$ac_file" mv "$ac_tmp/config.h" "$ac_file" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 fi else printf "%s\n" "/* $configure_input */" >&1 \ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \ || as_fn_error $? "could not create -" "$LINENO" 5 fi ;; esac done # for ac_tag as_fn_exit 0 _ACEOF ac_clean_files=$ac_clean_files_save test $ac_write_fail = 0 || as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 # configure is writing to config.log, and then calls config.status. # config.status does its own redirection, appending to config.log. # Unfortunately, on DOS this fails, as config.log is still kept open # by configure, so config.status won't be able to write to it; its # output is simply discarded. So we exec the FD to /dev/null, # effectively closing config.log, so it can be properly (re)opened and # appended to by config.status. When coming back to configure, we # need to make the FD available again. if test "$no_create" != yes; then ac_cs_success=: ac_config_status_args= test "$silent" = yes && ac_config_status_args="$ac_config_status_args --quiet" exec 5>/dev/null $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false exec 5>>config.log # Use ||, not &&, to avoid exiting from the if with $? = 1, which # would make configure fail if this is the last instruction. $ac_cs_success || as_fn_exit 1 fi # # CONFIG_SUBDIRS section. # if test "$no_recursion" != yes; then # Remove --cache-file, --srcdir, and --disable-option-checking arguments # so they do not pile up. ac_sub_configure_args= ac_prev= eval "set x $ac_configure_args" shift for ac_arg do if test -n "$ac_prev"; then ac_prev= continue fi case $ac_arg in -cache-file | --cache-file | --cache-fil | --cache-fi \ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) ac_prev=cache_file ;; -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* \ | --c=*) ;; --config-cache | -C) ;; -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) ac_prev=srcdir ;; -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) ;; -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) ac_prev=prefix ;; -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) ;; --disable-option-checking) ;; *) case $ac_arg in *\'*) ac_arg=`printf "%s\n" "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac as_fn_append ac_sub_configure_args " '$ac_arg'" ;; esac done # Always prepend --prefix to ensure using the same prefix # in subdir configurations. ac_arg="--prefix=$prefix" case $ac_arg in *\'*) ac_arg=`printf "%s\n" "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac ac_sub_configure_args="'$ac_arg' $ac_sub_configure_args" # Pass --silent if test "$silent" = yes; then ac_sub_configure_args="--silent $ac_sub_configure_args" fi # Always prepend --disable-option-checking to silence warnings, since # different subdirs can have different --enable and --with options. ac_sub_configure_args="--disable-option-checking $ac_sub_configure_args" ac_popdir=`pwd` for ac_dir in : $subdirs; do test "x$ac_dir" = x: && continue # Do not complain, so a configure script can configure whichever # parts of a large source tree are present. test -d "$srcdir/$ac_dir" || continue ac_msg="=== configuring in $ac_dir (`pwd`/$ac_dir)" printf "%s\n" "$as_me:${as_lineno-$LINENO}: $ac_msg" >&5 printf "%s\n" "$ac_msg" >&6 as_dir="$ac_dir"; as_fn_mkdir_p ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`printf "%s\n" "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`printf "%s\n" "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix cd "$ac_dir" # Check for configure.gnu first; this name is used for a wrapper for # Metaconfig's "Configure" on case-insensitive file systems. if test -f "$ac_srcdir/configure.gnu"; then ac_sub_configure=$ac_srcdir/configure.gnu elif test -f "$ac_srcdir/configure"; then ac_sub_configure=$ac_srcdir/configure else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: no configuration information is in $ac_dir" >&5 printf "%s\n" "$as_me: WARNING: no configuration information is in $ac_dir" >&2;} ac_sub_configure= fi # The recursion is here. if test -n "$ac_sub_configure"; then # Make the cache file name correct relative to the subdirectory. case $cache_file in [\\/]* | ?:[\\/]* ) ac_sub_cache_file=$cache_file ;; *) # Relative name. ac_sub_cache_file=$ac_top_build_prefix$cache_file ;; esac { printf "%s\n" "$as_me:${as_lineno-$LINENO}: running $SHELL $ac_sub_configure $ac_sub_configure_args --cache-file=$ac_sub_cache_file --srcdir=$ac_srcdir" >&5 printf "%s\n" "$as_me: running $SHELL $ac_sub_configure $ac_sub_configure_args --cache-file=$ac_sub_cache_file --srcdir=$ac_srcdir" >&6;} # The eval makes quoting arguments work. eval "\$SHELL \"\$ac_sub_configure\" $ac_sub_configure_args \ --cache-file=\"\$ac_sub_cache_file\" --srcdir=\"\$ac_srcdir\"" || as_fn_error $? "$ac_sub_configure failed for $ac_dir" "$LINENO" 5 fi cd "$ac_popdir" done fi if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 printf "%s\n" "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} fi librecast/configure.ac000066400000000000000000000134701502456746400153360ustar00rootroot00000000000000# -*- Autoconf -*- # Process this file with autoconf to produce a configure script. AC_PREREQ([2.71]) AC_INIT([librecast], [0.11.2], [bugs@librecast.net]) AC_SUBST(PACKAGE_ABIVERS, 0.6) AC_COPYRIGHT(Copyright (c) 2016-2025 Brett Sheffield See COPYING for license details. ) AC_CONFIG_SRCDIR([src/]) AC_CONFIG_HEADERS([src/config.h]) # Checks for programs. AC_PROG_CC AC_PROG_INSTALL AC_PROG_LN_S AC_CHECK_PROG([testrunner], [lctest], [lctest], [maketest]) AC_SUBST([TESTRUNNER],[$testrunner]) AC_CHECK_PROGS([FALSE], [false], [/usr/bin/env false]) AC_CHECK_PROG([ifconfig], [ifconfig], [ifconfig]) AC_SUBST([IFCONFIG],[$ifconfig]) AC_CHECK_PROG([iproute], [ip], [iproute]) AC_SUBST([IPROUTE],[$iproute]) AC_CHECK_PROG([ROUTE], [route], [route]) # Checks for libraries. AC_CHECK_LIB([dl], [dlsym]) AC_CHECK_LIB([m], [log2]) AC_CHECK_LIB([pthread], [pthread_create]) AC_SEARCH_LIBS([arc4random_uniform], [bsd]) AC_SEARCH_LIBS([clock_gettime], [rt]) AC_SEARCH_LIBS([__atomic_load_8], [atomic]) AC_ARG_WITH([mld], AS_HELP_STRING([--without-mld], [disable mld])) AC_ARG_WITH([blake3], AS_HELP_STRING([--with-blake3], [use BLAKE3 for hashing (default is yes)]) ) LIBBLAKE3= AS_IF([test "x$with_blake3" != xno], AC_SUBST([BLAKE3], [blake3]) AC_SUBST([LIBBLAKE3], [-lblake3]) AC_SUBST([INCBLAKE3], ["#include "]) AC_DEFINE([HAVE_BLAKE3], [1], [Define to 1 to use the `blake3' library for hashing.]) ) LIBMLD= AS_IF([test "x$with_mld" != "xno"], [ AC_SUBST([MLD], [libmld]) AC_SUBST([LIBMLD], [-lmld]) AC_SUBST([OBJMLD], [../libs/libmld/src/*.o]) AC_SUBST([MLD_HEADERS], [../libs/libmld/include/*.h]) AC_SUBST([INCMLD], ["-I ../libs/libmld"]) AC_DEFINE([HAVE_MLD], [1], [Define to 1 to use the MLD library.]) ]) AC_ARG_WITH([sodium], AS_HELP_STRING([--with-sodium], [use libsodium for encryption and \ hashing (default is yes, if available)]), [AC_SUBST([HAVE_LIBSODIUM], [])], [with_sodium=check]) LIBSODIUM= AS_IF([test "x$with_sodium" != xno], [AC_CHECK_LIB([sodium], [sodium_init], [AC_SUBST([LIBSODIUM], ["-lsodium"]) AC_SUBST([INCSODIUM], ["#include "]) AC_SUBST([HAVE_LIBSODIUM], ["HAVE_LIBSODIUM := 1"]) AC_DEFINE([HAVE_LIBSODIUM], [1], [Define to 1 if you have the `sodium' library (-lsodium).]) ], [if test "x$with_sodium" != xcheck; then AC_MSG_FAILURE([--with-sodium was given, but libsodium not found]) fi ], -lsodium)]) AS_IF([test "x$with_blake3" != xno], AC_SUBST([HASH_TYPE], ["#define HASH_TYPE HASH_BLAKE3"]) AC_SUBST([HASHSIZE], ["#define HASHSIZE BLAKE3_OUT_LEN"]) AC_SUBST([HASH_STATE], ["typedef blake3_hasher hash_state;"]) , AS_IF([test "x$with_sodium" != xno], [ AC_SUBST([HASH_TYPE], ["#define HASH_TYPE HASH_BLAKE2"]) AC_SUBST([HASHSIZE], ["#define HASHSIZE crypto_generichash_BYTES"]) AC_SUBST([HASH_STATE], ["typedef crypto_generichash_state hash_state;"]) ], [ AC_SUBST([HASH_TYPE], ["#undef HASH_TYPE"]) AC_SUBST([HASHSIZE], ["#undef HASHSIZE"]) ] ) ) AC_ARG_WITH([lcrq], AS_HELP_STRING([--with-lcrq], [use liblcrq for FEC \ (default is yes, if available)]), [AC_SUBST([HAVE_LIBLCRQ], [])], [with_lcrq=check]) LIBLCRQ= AS_IF([test "x$with_lcrq" != xno], [AC_CHECK_LIB([lcrq], [rq_init], [ AC_SUBST([LIBLCRQ], ["-llcrq"]) AC_SUBST([INCLUDE_LCRQ], ["#include "]) AC_SUBST([HAVE_LIBLCRQ], ["HAVE_LIBLCRQ := 1"]) AC_DEFINE([HAVE_LIBLCRQ], [1], [Define to 1 if you have the `lcrq' library (-llcrq).]) ], [if test "x$with_lcrq" != xcheck; then AC_MSG_FAILURE([--with-lcrq was given, but liblcrq not found]) fi ], -llcrq)]) AC_CHECK_LIB([lcrq], [rq_init]) AC_CHECK_FUNCS([rq_oti]) # Checks for header files. AC_CHECK_HEADERS([arpa/inet.h fcntl.h netdb.h netinet/in.h stdint.h sys/ioctl.h sys/param.h sys/socket.h unistd.h],[],AC_MSG_ERROR([required header file missing])) AC_CHECK_HEADERS([endian.h sys/endian.h libkern/OSByteOrder.h]) AC_CHECK_HEADERS([net/if_tap.h net/if_tun.h]) AC_CHECK_HEADERS([sys/time.h utime.h]) AC_CHECK_HEADERS([linux/netlink.h]) AC_CHECK_HEADER_STDBOOL # Checks for typedefs, structures, and compiler characteristics. AC_C_INLINE AC_C_RESTRICT AC_TYPE_INT16_T AC_TYPE_INT32_T AC_TYPE_INT64_T AC_TYPE_MODE_T AC_TYPE_OFF_T AC_TYPE_SIZE_T AC_TYPE_SSIZE_T AC_TYPE_UID_T AC_TYPE_UINT8_T AC_TYPE_UINT16_T AC_TYPE_UINT32_T AC_TYPE_UINT64_T AC_CHECK_TYPES([ptrdiff_t]) # Checks for library functions. AC_FUNC_CHOWN AC_FUNC_MMAP AC_FUNC_LSTAT_FOLLOWS_SLASHED_SYMLINK AC_CHECK_FUNCS([arc4random_uniform]) AC_CHECK_FUNCS([clock_gettime ftruncate getpagesize memset mkdir munmap pathconf realpath socket strdup strndup strerror strtoull],,AC_MSG_ERROR([required function missing])) AC_CHECK_FUNCS([epoll_create1 kqueue poll recvmmsg]) AC_CHECK_FUNCS([utimensat utimes]) AC_CHECK_FUNCS([recvmmsg]) AC_CHECK_FUNCS([rawmemchr memchr]) AC_CHECK_FUNCS([getcwd],,AC_MSG_WARN([required test function missing. Some tests may not function])) AC_CONFIG_FILES([Makefile doc/Makefile libs/Makefile libs/blake3/Makefile libs/blake3/c/Makefile src/Makefile test/Makefile examples/Makefile include/librecast/crypto.h include/librecast/types.h ]) if test "x$with_mld" != "xno"; then AC_CONFIG_SUBDIRS([libs/libmld]) fi AC_OUTPUT librecast/doc/000077500000000000000000000000001502456746400136105ustar00rootroot00000000000000librecast/doc/Makefile.in000066400000000000000000000004721502456746400156600ustar00rootroot00000000000000PREFIX ?= @prefix@ .PHONY: clean doc install realclean doc: install install: install -d $(DESTDIR)$(PREFIX)/share/man/man3 install *.3 $(DESTDIR)$(PREFIX)/share/man/man3/ install -d $(DESTDIR)$(PREFIX)/share/man/man7 install *.7 $(DESTDIR)$(PREFIX)/share/man/man7/ clean: realclean: clean $(RM) Makefile librecast/doc/RELEASE-PROCESS.md000066400000000000000000000015201502456746400163240ustar00rootroot00000000000000# Librecast Release Process Releases are prepared from the `main` git branch. The `testing` branch is then rebased from this and a Release Candidate is prepared (eg. 0.6-RC1). ## Update CHANGELOG.md - Check `git log` and add anything relevant for release. - Replace Unreleased with version number and date. ## configure - Update version number, copyright year etc. in configure.ac - run autoconf ## test Run make test / make check as user and root. ## Rebase testing branch from main ``` git checkout testing git rebase main ``` ## Tag Release Candidate eg. `git tag -a v0.6-RC1` ## Push RC and tag ## Testing on all supported platforms. ## Coverity testing ## Fixes If fixes required, push another RC and repeat. ## When all testing passes, tag the release ## Rebase release branch ``` git checkout release git rebase main ``` librecast/doc/lc_channel_check_seqno.3000066400000000000000000000000421502456746400203200ustar00rootroot00000000000000.so man3/lc_channel_detect_gaps.3 librecast/doc/lc_channel_coding_set.3000066400000000000000000000036021502456746400201610ustar00rootroot00000000000000.TH LC_CHANNEL_CODING_SET 3 2023-07-31 "LIBRECAST" "Librecast Programmer's Manual" .SH NAME lc_ctx_coding_set, lc_channel_coding_set - set Librecast channel encoding options .SH LIBRARY Librecast library .RI ( liblibrecast ", " \-llibrecast ) .SH SYNOPSIS .nf .B #include .PP .BI "int lc_ctx_coding_set(lc_ctx_t *" ctx ", int " coding ");" .BI "int lc_channel_coding_set(lc_channel_t *" chan ", int " coding ");" .fi .PP Compile and link with \fI\-llibrecast\fP. .SH DESCRIPTION .BR lc_ctx_coding_set () sets the default encoding options for sockets and channels subsequently created using context .IR ctx . .PP .BR lc_channel_coding_set () sets encoding options for a Librecast channel, .IR chan , overriding any defaults inherited from the parent Librecast context. .PP .I chan is a pointer to a Librecast channel. .PP The .I coding argument can include the bitwise OR of any of the following coding options: .TP .B LC_CODE_SYMM Enable symmetric key encryption. Requires that a symmetric key has been assigned to the Channel with .I lc_channel_set_sym_key(3) .TP .B LC_CODE_FEC_RQ Enables RaptorQ Forwards Error Correction (FEC). Calling .I lc_channel_send(3) as normal encodes the data to be sent. Subsequent calls to .I lc_channel_send() with .I buf == NULL will send the next symbol/packet. To receive, call .I lc_channel_coding_set (chan, LC_CODE_FEC_RQ) on the receiver and then .I lc_channel_recv(). Encodings are per channel, not per socket, so it is necessary to use .I lc_channel_recv(), not .I lc_socket_recv(3). .TP .B LC_CODE_FEC_RAND Requires .B LC_CODE_FEC_RQ. Use random symbols instead of sequential ESIs. .SH RETURN VALUE Returns the current value of the channel coding options. .SH ERRORS None. .SH SEE ALSO .BR lc_channel_new (3), .BR lc_channel_close (3), .BR lc_channel_send (3), .BR lc_channel_set_sym_key (3), .BR lc_ctx_new (3), .BR lc_socket_setopt (3), .BR lc_socket_recv (3) librecast/doc/lc_channel_detect_gaps.3000066400000000000000000000064341502456746400203330ustar00rootroot00000000000000.TH LC_CHANNEL_DETECT_GAPS 3 2022-10-29 "LIBRECAST" "Librecast Programmer's Manual" .SH NAME lc_channel_detect_gaps, lc_channel_check_seqno \- check for missing incoming messages and send NACK messages if required .SH LIBRARY Librecast library .RI ( liblibrecast ", " \-llibrecast ) .SH SYNOPSIS .nf .B #include .PP .BI "int lc_channel_detect_gaps(lc_channel_t *chan);" .BI "int lc_channel_check_seqno(lc_channel_t *chan, lc_seq_t seq);" .fi .PP Compile and link with \fI\-llibrecast\fP. .SH DESCRIPTION .BR lc_channel_detect_gaps () arranges for a channel to check message sequence numbers of recently received messages and to send NACK messages if it detects gaps. These NACK messages will cause the sender to resend the missing messages, which will then arrive as normal. The application needs to receive messages using .BR lc_msg_recv () or .BR lc_socket_listen () which decode the incoming messages and extract the sequence numbers, and will then automatically detect gaps. .PP .BR lc_channel_check_seqno () compares the sequence number passed to it with the sequence numbers of recent messages and sends NACKs if any are deemed missing: it is necessary to call this if an application uses its own message format, and receives messages using functions other than .BR lc_msg_recv () or .BR lc_socket_listen () because the library will not have the information necessary to extract sequence numbers from messages; however the library will still take care of gap detection and NACK messages. The second argument must be the sequence number from the message as decoded by the application. It is necessary to call .BR lc_channel_detect_gaps () before using .BR lc_channel_check_seqno () otherwise the function will not do anything. This could be useful for example if gap detection and NACKs are optional, and the application will conditionally call .BR lc_channel_detect_gaps () during initialisation, but then can just unconditionally call .BR lc_channel_check_seqno () after decoding each incoming message. .SH RETURN VALUE .BR lc_channel_detect_gaps () returns 0 on success, and -1 to indicate an error, setting the global variable .I errno to an appropriate code, most likely .BR ENOMEM to indicate that there was insufficient memory to set up the required data structures. .PP .BR lc_channel_detect_gaps () returns 0 if the message is new, 1 if it is a duplicate (the sequence number has already been seen) and -1 to indicate an error transmitting a NACK message, setting .I errno to an appropriate code. .SH ERRORS .BR lc_channel_detect_gaps () can fail with any of the errors the .BR malloc () library function can produce, as well as any errors produces by the .BR lc_channel_sidehash () or .BR lc_socket_new () functions. .PP .BR lc_channel_check_seqno () can fail with any of the errors the .BR lc_socket_send () function can produce. .SH EXAMPLE .SS Program source \& .EX lc_ctx_t *lctx; lc_channel_t *chan; lctx = lc_ctx_new(); chan = lc_channel_new(lctx, "channel name"); if (lc_channel_detect_gaps(chan) == -1) { /* handle this error */ } /* your program goes here, likely calling lc_msg_recv(chan, ...) or lc_socket_listen(...) */ lc_channel_free(chan); lc_ctx_free(lctx); .EE .SH SEE ALSO .BR lc_channel_nack_handler (3), .BR lc_channel_free (3), .BR lc_msg_recv (3), .BR lc_socket_listen (3), .BR lc_socket_send (3) librecast/doc/lc_channel_filter_set.3000066400000000000000000000015761502456746400202130ustar00rootroot00000000000000.TH LC_CHANNEL_FILTER_SET 3 2025-04-02 "LIBRECAST" "Librecast Programmer's Manual" .SH NAME lc_channel_filter_set \- set filter for channel .SH LIBRARY Librecast library .RI ( liblibrecast ", " \-llibrecast ) .SH SYNOPSIS .nf .B #include .PP .BI "void lc_channel_filter_set(lc_channel_t " *chan ", lc_filter_t " *filter ");" .fi .PP Compile and link with \fI\-llibrecast\fP. .SH DESCRIPTION .BR lc_channel_filter_set () applies .IR filter to the channel .IR chan for receiving. .PP Packets which do not match this filter will be dropped silently, and calls to recv functions like .BR lc_channel_recv (3) will not return until a packet is received which passes the filter. .SH RETURN VALUE None. .SH ERRORS None. .SH SEE ALSO .BR lc_keyring_add (3), .BR lc_keyring_del (3), .BR lc_keyring_init (3), .BR lc_keyring_free (3), .BR lc_channel_token_set (3), .BR lc_channel_new (3) librecast/doc/lc_channel_getkey.3000066400000000000000000000000311502456746400173240ustar00rootroot00000000000000.so man3/lc_ctx_getkey.3 librecast/doc/lc_channel_nack_add_log.3000066400000000000000000000000431502456746400204240ustar00rootroot00000000000000.so man3/lc_channel_nack_handler.3 librecast/doc/lc_channel_nack_handler.3000066400000000000000000000102561502456746400204570ustar00rootroot00000000000000.TH LC_CHANNEL_NACK_HANDLER 3 2022-10-29 "LIBRECAST" "Librecast Programmer's Manual" .SH NAME lc_channel_nack_handler, lc_channel_nack_handler_thr, lc_channel_nack_add_log \- outgoing message logging to handle NACK and replay requests .SH LIBRARY Librecast library .RI ( liblibrecast ", " \-llibrecast ) .SH SYNOPSIS .nf .B #include .PP .BI "int lc_channel_nack_handler(lc_channel_t *chan, int n_seconds);" .BI "int lc_channel_nack_handler_thr(lc_channel_t *chan, int n_seconds, void *(*nack_thread)(void *));" .BI "int lc_channel_nack_add_log(lc_channel_t *chan, const void *buf, size_t len, lc_seq_t seq);" .fi .PP Compile and link with \fI\-llibrecast\fP. .SH DESCRIPTION .BR lc_channel_nack_handler () sets up a per-channel buffer to keep a copy of outgoing messages sent via .BR lc_msg_send () and also starts a new thread (called "nack thread") to handle any retransmission requests; the outgoing messages are kept for at least .I n_seconds seconds if there is sufficient free memory to do so. The nack thread listens for messages on a related channel, interprets them as NACK messages, and arranges for retransmission of the corresponding messages. The normal case is that these NACK messages are generated as a result of calling .BR lc_channel_detect_gaps () on the receiver side. A call to .BR lc_channel_free (3) will stop the nack thread if it's running. .PP .BR lc_channel_nack_handler_thr () is similar to .BR lc_channel_nack_handler () except that it specifies a different function to use for the nack thread; it will be called in a new thread with an opened channel and socket where it can receive NACK messages, and another channel it can use to resend packets; currently, there is no alternative thread to use, and this function is only used by the library's tests; however a different nack thread could be provided in future for example to deal with the special case of messages sent from static data, which can be resent without storing recent messages in a memory buffer. .PP .BR lc_channel_nack_add_log () adds a message to the internal memory buffer, making it available for retransmission as a result of a NACK; it is not normally necessary to call this function if all messages are sent using .BR lc_msg_send () however an application which defines its own message format will need to call .BR lc_channel_nack_add_log () with a copy of each message as it goes on the wire, as well as the sequence number it contains, as the library will have no way to find this information in the applicatin's own message format. The application needs to call .BR lc_channel_nack_handler () before using .BR lc_channel_nack_add_log () otherwise the call will not log anything: this could be useful if message logging and NACK request handling is optional, so the application can conditionally call .BR lc_channel_nack_handler () during initialisation, but then unconditionally call .BR lc_channel_nack_add_log () for each message it sends. .SH RETURN VALUE .BR lc_channel_nack_handler () and .BR lc_channel_nack_handler_thr () return 0 on success, and -1 to indicate an error, setting the global variable .I errno to an appropriate code, most likely .BR ENOMEM to indicate that there was insufficient memory to set up the required data structures. .PP The .BR lc_channel_nack_add_log () function returns 0 on success and -1 to indicate that there was no memory to store the message in its internal buffers, setting .I errno to the value .BR ENOMEM .SH ERRORS .BR lc_channel_nack_handler () and .BR lc_channel_nack_handler_thr () can fail with any of the errors the .BR malloc () library function can produce, as well as any errors produces by the .BR lc_channel_sidehash () or .BR lc_socket_new () functions. .PP .BR lc_channel_nack_add_log () can fail with any of the errors the .BR malloc () library function can produce. .SH EXAMPLE .SS Program source \& .EX lc_ctx_t *lctx; lc_channel_t *chan; lctx = lc_ctx_new(); chan = lc_channel_new(lctx, "channel name"); if (lc_channel_nack_handler(chan, 10) == -1) { /* handle this error */ } /* your program goes here, likely calling lc_msg_send(chan, ...) */ lc_channel_free(chan); lc_ctx_free(lctx); .EE .SH SEE ALSO .BR lc_channel_detect_gaps (3), .BR lc_channel_free (3), .BR lc_msg_send (3) librecast/doc/lc_channel_nack_handler_thr.3000066400000000000000000000000431502456746400213250ustar00rootroot00000000000000.so man3/lc_channel_nack_handler.3 librecast/doc/lc_channel_oti_peek.3000066400000000000000000000023321502456746400176410ustar00rootroot00000000000000.TH LC_CHANNEL_OTI_PEEK 3 2022-07-06 "LIBRECAST" "Librecast Programmer's Manual" .SH NAME lc_channel_oti_peek - peek at OTI header .SH LIBRARY Librecast library .RI ( liblibrecast ", " \-llibrecast ) .SH SYNOPSIS .nf .B #include .PP .BI "int lc_channel_oti_peek(lc_channel_t " *chan ", rq_oti_t " *oti ", rq_scheme_t " *scheme ");" .fi .PP Compile and link with \fI\-llibrecast\fP. .SH DESCRIPTION The .BR lc_channel_oti_peek () function peeks at the OTI header (RaptorQ FEC Object Transmission Information header - see RFC 6330) in the next packet of the socket bound to channel .I chan and sets .IR oti and .IR scheme accordingly. .SH RETURN VALUE .BR lc_channel_oti_peek () returns zero on success. On error, -1 is returned, and .I errno is set to indicate the error. .SH ERRORS .TP .BR EBADMSG The header is malformed, or T does not match the expected value for .IR chan . .PP .I errno can also be set to any of the errors returned by .BR lc_socket_recv (3) .PP .SH SEE ALSO .BR lc_channel_new (3), .BR lc_channel_close (3), .BR lc_channel_recv (3), .BR lc_channel_coding_set (3), .BR lc_socket_recv (3) .BR rq_pid2sbn (3), .BR rq_pid2esi (3), .BR rq_pidset (3), .BR rq_pidsetsbn (3), .BR rq_pidsetesi (3), .BR lcrq (7) librecast/doc/lc_channel_ratelimit.3000066400000000000000000000000341502456746400200310ustar00rootroot00000000000000.so man3/lc_ctx_ratelimit.3 librecast/doc/lc_channel_rq.3000066400000000000000000000013001502456746400164560ustar00rootroot00000000000000.TH LC_CHANNEL_RQ 3 2023-07-23 "LIBRECAST" "Librecast Programmer's Manual" .SH NAME lc_channel_rq \- return lcrq handle for channel .SH LIBRARY Librecast library .RI ( liblibrecast ", " \-llibrecast ) .SH SYNOPSIS .nf .B #include .PP .BI "rq_t *lc_channel_rq(lc_channel_t " *chan ");" .fi .PP Compile and link with \fI\-llibrecast\fP. .SH DESCRIPTION The .BR lc_channel_rq function returns the lcrq (RaptorQ) handle for channel .IR chan . .PP .SH RETURN VALUE The .BR lc_channel_rq function returns a pointer to the lcrq handle associated with the channel, or NULL if none set. .SH ERRORS None. .SH SEE ALSO .BR lc_ctx_new (3), .BR lc_ctx_free (3), .BR lc_channel_new (3), .BR lcrq (7) librecast/doc/lc_channel_rq_overhead.3000066400000000000000000000026261502456746400203470ustar00rootroot00000000000000.TH LC_CHANNEL_RQ_OVERHEAD 3 2025-03-24 "LIBRECAST" "Librecast Programmer's Manual" .SH NAME lc_ctx_coding_set, lc_channel_rq_overhead - set Librecast RaptorQ overhead packets .SH LIBRARY Librecast library .RI ( liblibrecast ", " \-llibrecast ) .SH SYNOPSIS .nf .B #include .PP .BI "int lc_ctx_rq_overhead(lc_ctx_t *" ctx ", int " overhead ");" .BI "int lc_channel_rq_overhead(lc_channel_t *" chan ", int " overhead ");" .fi .PP Compile and link with \fI\-llibrecast\fP. .SH DESCRIPTION .BR lc_ctx_rq_overhead () sets the default overhead packets for channels subsequently created using context .IR ctx . .PP .BR lc_channel_rq_overhead () sets RaptorQ overhead packets for a Librecast channel, .IR chan , overriding any defaults inherited from the parent Librecast context. .PP .I chan is a pointer to a Librecast channel. .PP The .I overhead argument is the number of overhead packets to send in a single call to .I lc_channel_send(3) or .I lc_channel_sendmsg(3) . If >= 0, a single call to a sending function with LC_CODE_FEC_RQ enabled will cause K' + overhead packets to be sent. .PP If < 0, no automatic sending will occur. .SH RETURN VALUE Returns the new overhead value. .SH ERRORS None. .SH SEE ALSO .BR lc_channel_new (3), .BR lc_channel_close (3), .BR lc_channel_send (3), .BR lc_channel_sendmsg (3), .BR lc_channel_set_sym_key (3), .BR lc_ctx_new (3), .BR lc_socket_setopt (3), .BR lc_socket_recv (3) librecast/doc/lc_channel_send.3000066400000000000000000000025311502456746400167740ustar00rootroot00000000000000.TH LC_CHANNEL_SEND 3 2023-08-09 "LIBRECAST" "Librecast Programmer's Manual" .SH NAME lc_channel_send, lc_channel_sendmsg \- send data on a Librecast channel .SH LIBRARY Librecast library .RI ( liblibrecast ", " \-llibrecast ) .SH SYNOPSIS .nf .B #include .PP .BI "ssize_t lc_channel_send(lc_channel_t "*chan ", const void " *buf ", size_t " len ", int " flags ")" .BI "ssize_t lc_channel_sendmsg(lc_channel_t " *chan ", struct msghdr " *msg ", int " flags ");" .fi .PP Compile and link with \fI\-llibrecast\fP. .SH DESCRIPTION Each of these functions sends data over multicast on the librecast channel .IR chan . They are analogous to the .BR send (2) and .BR sendmsg (2) calls. .PP In addition to the usual flags used with .BR send (2) and .BR sendmsg (2) these functions support the following flags: .TP .BR MSG_DROP This flag causes the packet to be dropped instead of sending. It is used for testing. All normal processing, such as encoding proceeds as usual. Only the final send syscall is skipped. The return value will be the number of bytes that would have been sent. .SH RETURN VALUE These calls return the number of bytes received, or -1 if an error occurred. In the event of an error, .I errno is set to indicate the error. .SH ERRORS See .BR send (2). .SH SEE ALSO .BR lc_ctx_new(3), .BR lc_channel_new (3), .BR send (2), .BR sendmsg (2) librecast/doc/lc_channel_sendmsg.3000066400000000000000000000000331502456746400174760ustar00rootroot00000000000000.so man3/lc_channel_send.3 librecast/doc/lc_channel_set_pub_key.3000066400000000000000000000000361502456746400203520ustar00rootroot00000000000000.so man3/lc_ctx_set_sym_key.3 librecast/doc/lc_channel_set_sym_key.3000066400000000000000000000000361502456746400203740ustar00rootroot00000000000000.so man3/lc_ctx_set_sym_key.3 librecast/doc/lc_channel_setkey.3000066400000000000000000000000311502456746400173400ustar00rootroot00000000000000.so man3/lc_ctx_getkey.3 librecast/doc/lc_channel_token_set.3000066400000000000000000000013151502456746400200350ustar00rootroot00000000000000.TH LC_CHANNEL_TOKEN_SET 3 2025-04-02 "LIBRECAST" "Librecast Programmer's Manual" .SH NAME lc_channel_token_set \- set token for channel .SH LIBRARY Librecast library .RI ( liblibrecast ", " \-llibrecast ) .SH SYNOPSIS .nf .B #include .PP .BI "void lc_channel_token_set(lc_channel_t " *chan ", lc_token_t " *token ");" .fi .PP Compile and link with \fI\-llibrecast\fP. .SH DESCRIPTION .BR lc_channel_token_set () sets .IR token as the capability token to use when sending on channel .IR chan . .SH RETURN VALUE None. .SH ERRORS None. .SH SEE ALSO .BR lc_keyring_add (3), .BR lc_keyring_del (3), .BR lc_keyring_init (3), .BR lc_keyring_free (3), .BR lc_channel_filter_set (3), .BR lc_channel_new (3) librecast/doc/lc_ctx_coding_set.3000066400000000000000000000000411502456746400173410ustar00rootroot00000000000000.so man3/lc_channel_coding_set.3 librecast/doc/lc_ctx_free.3000066400000000000000000000000261502456746400161470ustar00rootroot00000000000000.so man3/lc_ctx_new.3 librecast/doc/lc_ctx_getkey.3000066400000000000000000000030111502456746400165130ustar00rootroot00000000000000.TH LC_CTX_GETKEY 3 2023-07-31 "LIBRECAST" "Librecast Programmer's Manual" .SH NAME lc_ctx_getkey, lc_ctx_setkey, lc_channel_getkey, lc_channel_setkey - set Librecast channel encoding options .SH LIBRARY Librecast library .RI ( liblibrecast ", " \-llibrecast ) .SH SYNOPSIS .nf .B #include .PP .BI "int lc_ctx_getkey(lc_ctx_t " *ctx ", lc_key_t " *key ", int " type ");" .BI "int lc_ctx_setkey(lc_ctx_t " *ctx ", lc_key_t " *key ", int " type ");" .BI "int lc_channel_getkey(lc_channel_t " *chan ", lc_key_t " *key ", int " type ");" .BI "int lc_channel_setkey(lc_channel_t " *chan ", lc_key_t " *key ", int " type ");" .fi .PP Compile and link with \fI\-llibrecast\fP. .SH DESCRIPTION These functions get or set keys for a Librecast context .IR ctx or channel .IR chan . .PP .IR is a pointer to an lc_key_t structure. The set functions will use this to set the key on the context or channel, and the set functions will return a copy of the current key in this structure. .PP The .I type argument must be one of the following options: .TP .B LC_CODE_SYMM Symmetric key. .TP .B LC_CODE_PUBK Public key. .PP .SH RETURN VALUE These functions return zero on success. On error, -1 is returned and .BR errno is set to indicate the error. .SH ERRORS .TP .BR EINVAL Invalid argument. .PP .SH SEE ALSO .BR lc_ctx_coding_set (3), .BR lc_channel_new (3), .BR lc_channel_close (3), .BR lc_channel_coding_set (3), .BR lc_channel_send (3), .BR lc_channel_set_sym_key (3), .BR lc_ctx_new (3), .BR lc_socket_setopt (3), .BR lc_socket_recv (3) librecast/doc/lc_ctx_ifx.3000066400000000000000000000014211502456746400160140ustar00rootroot00000000000000.TH LC_CTX_IFX 3 2023-07-23 "LIBRECAST" "Librecast Programmer's Manual" .SH NAME lc_ctx_ifx \- set default interface for sockets and channels created with this context .SH LIBRARY Librecast library .RI ( liblibrecast ", " \-llibrecast ) .SH SYNOPSIS .nf .B #include .PP .BI "void lc_ctx_ifx(lc_ctx_t " *ctx ", unsigned int " ifx ");" .fi .PP Compile and link with \fI\-llibrecast\fP. .SH DESCRIPTION The .BR lc_ctx_ifx function sets the default interface to .IR ifx for subsequent sockets and channels created with context .IR ctx . A value of 0 for .IR ifx means all interfaces. .PP .SH RETURN VALUE The .BR lc_ctx_ifx () function returns no value. .SH ERRORS None. .SH SEE ALSO .BR lc_ctx_new (3), .BR lc_ctx_free (3), .BR lc_socket_new (3), .BR lc_channel_new (3) librecast/doc/lc_ctx_new.3000066400000000000000000000022621502456746400160230ustar00rootroot00000000000000.TH LC_CTX_NEW 3 2020-08-01 "LIBRECAST" "Librecast Programmer's Manual" .SH NAME lc_ctx_new, lc_ctx_free \- create and free Librecast contexts .SH LIBRARY Librecast library .RI ( liblibrecast ", " \-llibrecast ) .SH SYNOPSIS .nf .B #include .PP .BI "lc_ctx_t *lc_ctx_new(void);" .BI "void lc_ctx_free(lc_ctx_t " "*ctx" ); .fi .PP Compile and link with \fI\-llibrecast\fP. .SH DESCRIPTION .BR lc_ctx_new () creates a new Librecast context and sets up the environment. Call .BR lc_ctx_free (3) when done. .PP .BR lc_ctx_free () invalidates and frees a Librecast context created with .BR lc_ctx_new (3) . .SH RETURN VALUE .BR lc_ctx_new () returns a pointer to a .I lc_ctx_t handle. On error returns NULL and sets .I errno to .BR ENOMEM . .PP The .BR lc_ctx_free () function returns no value. .SH ERRORS .BR lc_ctx_new () can fail with the following error: .TP .B ENOMEM Out of memory. Possibly, the application hit the .BR RLIMIT_AS or .BR RLIMIT_DATA limit described in .BR getrlimit (2). .SH EXAMPLE .SS Program source \& .EX lc_ctx_t *lctx; lctx = lc_ctx_new(); /* your Librecast program here */ lc_ctx_free(lctx); /* free context when done */ .EE .SH SEE ALSO .BR lc_ctx_free (3) librecast/doc/lc_ctx_ratelimit.3000066400000000000000000000024061502456746400172240ustar00rootroot00000000000000.TH LC_CTX_RATELIMIT 3 2023-07-23 "LIBRECAST" "Librecast Programmer's Manual" .SH NAME lc_ctx_ratelimit, lc_channel_ratelimit \- set send/recv ratelimits .SH LIBRARY Librecast library .RI ( liblibrecast ", " \-llibrecast ) .SH SYNOPSIS .nf .B #include .PP .BI "void lc_ctx_ratelimit(lc_ctx_t " *ctx ", size_t " bps_out ", size_t " bps_in ");" .BI "void lc_channel_ratelimit(lc_channel_t " *chan ", size_t " bps_out ", size_t " bps_in ");" .fi .PP Compile and link with \fI\-llibrecast\fP. .SH DESCRIPTION The .BR lc_ctx_ratelimit function sets the default ratelimits for subsequent sockets and channels created with context .IR ctx . .PP .IR bps_out and .IR bps_in specify the ratelimits in bits per second for outbound (send) and inbound (recv) respectively. These limits are applied to future sockets and channels created with .BR lc_socket_new (3) and .BR lc_channel_new (3). Existing sockets and channels are unaffected. .PP .BR lc_channel_ratelimit (3) sets the rate limits for channel .IR chan similarly. .PP .SH RETURN VALUE These functions return no value. .SH ERRORS None. .SH NOTES Only the send limit is enforced at this time. .SH SEE ALSO .BR lc_ctx_new (3), .BR lc_ctx_free (3), .BR lc_socket_new (3), .BR lc_channel_new (3), .BR lc_channel_ratelimit (3) librecast/doc/lc_ctx_rq_overhead.3000066400000000000000000000000421502456746400175230ustar00rootroot00000000000000.so man3/lc_channel_rq_overhead.3 librecast/doc/lc_ctx_set_pub_key.3000066400000000000000000000000361502456746400175400ustar00rootroot00000000000000.so man3/lc_ctx_set_sym_key.3 librecast/doc/lc_ctx_set_sym_key.3000066400000000000000000000037011502456746400175640ustar00rootroot00000000000000.TH LC_CTX_SET_SYM_KEY 3 2023-07-31 "LIBRECAST" "Librecast Programmer's Manual" .SH NAME lc_ctx_set_sym_key, lc_ctx_set_pub_key, lc_channel_set_sym_key, lc_channel_set_pub_key - set Librecast channel encoding keys .SH LIBRARY Librecast library .RI ( liblibrecast ", " \-llibrecast ) .SH SYNOPSIS .nf .B #include .PP .BI "int lc_ctx_set_sym_key(lc_ctx_t " *ctx ", unsigned char " *key ", size_t " len ");" .BI "int lc_ctx_set_pub_key(lc_ctx_t " *ctx ", unsigned char " *key ", size_t " len ");" .BI "int lc_channel_set_sym_key(lc_channel_t " *chan ", unsigned char " *key ", size_t " len ");" .BI "int lc_channel_set_pub_key(lc_channel_t " *chan ", unsigned char " *key ", size_t " len" );" .fi .PP Compile and link with \fI\-llibrecast\fP. .SH DESCRIPTION These functions set encryption keys for a Librecast context .IR ctx or channel .IR chan . .PP The .BR lc_ctx_set_sym_key () function sets a symmetric .IR key of length .IR len on a Librecast context. This key will be used by default by any channels subsequently created using the context. Any existing channels will retain their existing key. .PP The .BR lc_ctx_set_pub_key () function sets a public .IR key of length .IR len on a Librecast context. This key will be used by default by any channels subsequently created using the context. Any existing channels will retain their existing key. .PP The .BR lc_channel_set_sym_key () function sets a symmetric .IR key of length .IR len on a Librecast channel. .PP The .BR lc_channel_set_pub_key () function sets a public .IR key of length .IR len on a Librecast channel. .PP .SH RETURN VALUE These functions return zero on success. On error, -1 is returned and .BR errno is set to indicate the error. .SH ERRORS .TP .BR EINVAL Invalid argument. .PP .SH SEE ALSO .BR lc_ctx_coding_set (3), .BR lc_channel_new (3), .BR lc_channel_close (3), .BR lc_channel_coding_set (3), .BR lc_channel_send (3), .BR lc_ctx_new (3), .BR lc_socket_setopt (3), .BR lc_socket_recv (3) librecast/doc/lc_ctx_setkey.3000066400000000000000000000000311502456746400165260ustar00rootroot00000000000000.so man3/lc_ctx_getkey.3 librecast/doc/lc_hashtoaddr.3000066400000000000000000000023031502456746400164710ustar00rootroot00000000000000.TH LC_HASHTOADDR 3 2023-07-23 "LIBRECAST" "Librecast Programmer's Manual" .SH NAME lc_hashtoaddr - create IPv6 multicast addr from supplied hash and flags .SH LIBRARY Librecast library .RI ( liblibrecast ", " \-llibrecast ) .SH SYNOPSIS .nf .B #include .PP .BI "void lc_hashtoaddr(struct in6_addr " *addr ", unsigned char " *hash ", size_t " hashlen ", .BI " unsigned char " flags ");" .fi .PP Compile and link with \fI\-llibrecast\fP. .SH DESCRIPTION The .BR lc_hashtoaddr () function creates and returns an IPv6 multicast address in .IR addr from the supplied .IR hash of length .IR hashlen and .IR flags . .PP The address returned in .IR addr is a valid IPv6 multicast address. The first 8 bits are set to 1. The following 8 bits are set to .IR flags , which should be the valid IPv6 multicast 4 bit flags field as defined in IETF RFC 4291, followed by the 4 bits for multicast scope. The first 14 bytes of .IR hash are used for the remaining 14 bytes of the address. .SH RETURN VALUE The lc_hashtoaddr () function returns no value. .SH ERRORS None. .SH SEE ALSO .BR lc_channel_new (3), .BR lc_channel_close (3), .BR lc_ctx_new (3), .BR lc_socket_new (3), .BR lc_channel_new (3) librecast/doc/lc_keypair_new.3000066400000000000000000000020211502456746400166620ustar00rootroot00000000000000.TH LC_KEYPAIR_NEW 3 2025-04-02 "LIBRECAST" "Librecast Programmer's Manual" .SH NAME lc_keypair_new \- create new keypair .SH LIBRARY Librecast library .RI ( liblibrecast ", " \-llibrecast ) .SH SYNOPSIS .nf .B #include .PP .BI "int lc_keypair_new(lc_keypair_t " *keypair ", int " flags ");" .fi .PP Compile and link with \fI\-llibrecast\fP. .SH DESCRIPTION .BR lc_keypair_new () creates a new signing or encryption keypair. .PP The new keypair will be returned in .IR keypair . .PP .I flags can be any of the following: .TP .B LC_KEY_SIG Generate a signing keypair. .TP .B LC_KEY_ENC Generate an encryption keypair. .SH RETURN VALUE .BR lc_keypair_new () returns 0 if the call succeeds, or -1 if an error occurred. In the event of an error, .I errno is set to indicate the error. .SH ERRORS .BR lc_keypair_new () can fail with the following errors: .TP .B EINVAL Key generation failed. .PP .SH SEE ALSO .BR lc_keyring_init (3), .BR lc_keyring_free (3), .BR lc_keyring_add (3), .BR lc_keyring_del (3), .BR lc_token_new (3) librecast/doc/lc_keyring_add.3000066400000000000000000000023511502456746400166330ustar00rootroot00000000000000.TH LC_KEYRING_ADD 3 2025-04-02 "LIBRECAST" "Librecast Programmer's Manual" .SH NAME lc_keyring_add, lc_keyring_del \- add and remove keys to/from a keyring .SH LIBRARY Librecast library .RI ( liblibrecast ", " \-llibrecast ) .SH SYNOPSIS .nf .B #include .PP .BI "int lc_keyring_add(lc_keyring_t " *keyring ", uint8_t " *key ");" .BI "int lc_keyring_del(lc_keyring_t " *keyring ", uint8_t " *key ");" .fi .PP Compile and link with \fI\-llibrecast\fP. .SH DESCRIPTION .BR lc_keyring_add () adds .IR key to .IR keyring . .PP .BR lc_keyring_del () removes .IR key from .IR keyring . .PP .IR keyring is a pointer to the keyring to manage. .PP .IR key is a pointer to the key to add. .SH RETURN VALUE These functions return 0 if the call succeeds, or -1 if an error occurred. In the event of an error, .I errno is set to indicate the error. .SH ERRORS .BR lc_keyring_add can fail with the following errors: .TP .B ENOMEM Not enough space to add key. Keyring is full. .PP .BR lc_keyring_del can fail with the following errors: .TP .B ENOKEY The requested key could not be found. .SH SEE ALSO .BR lc_keyring_init (3), .BR lc_keyring_free (3), .BR lc_keyring_has (3), .BR lc_channel_filter_set (3), .BR lc_channel_new (3), .BR lc_keypair_new (3), librecast/doc/lc_keyring_del.3000066400000000000000000000000321502456746400166410ustar00rootroot00000000000000.so man3/lc_keyring_add.3 librecast/doc/lc_keyring_free.3000066400000000000000000000000331502456746400170170ustar00rootroot00000000000000.so man3/lc_keyring_init.3 librecast/doc/lc_keyring_has.3000066400000000000000000000012761502456746400166630ustar00rootroot00000000000000.TH LC_KEYRING_HAS 3 2025-04-02 "LIBRECAST" "Librecast Programmer's Manual" .SH NAME lc_keyring_has \- search keyring for key .SH LIBRARY Librecast library .RI ( liblibrecast ", " \-llibrecast ) .SH SYNOPSIS .nf .B #include .PP .BI "int lc_keyring_has(lc_keyring_t " *keyring ", uint8_t " *key ");" .fi .PP Compile and link with \fI\-llibrecast\fP. .SH DESCRIPTION Searches .IR keyring for .IR key . .SH RETURN VALUE .BR lc_keyring_has () returns -1 if .IR key is found on keyring, or 0 if not found. .SH ERRORS None. .SH SEE ALSO .BR lc_keyring_init (3), .BR lc_keyring_free (3), .BR lc_keyring_has (3), .BR lc_channel_filter_set (3), .BR lc_channel_new (3), .BR lc_keypair_new (3), librecast/doc/lc_keyring_init.3000066400000000000000000000023651502456746400170530ustar00rootroot00000000000000.TH LC_KEYRING_INIT 3 2025-04-02 "LIBRECAST" "Librecast Programmer's Manual" .SH NAME lc_keyring_init \- initialize keyring .SH LIBRARY Librecast library .RI ( liblibrecast ", " \-llibrecast ) .SH SYNOPSIS .nf .B #include .PP .BI "int lc_keyring_init(lc_keyring_t " *keyring ", size_t " nkeys ");" .PP .BI "void lc_keyring_free(lc_keyring_t " *keyring ");" .fi .PP Compile and link with \fI\-llibrecast\fP. .SH DESCRIPTION .BR lc_keyring_init () initializes a keyring for use with tokens and filters. .PP .BR lc_keyring_free () frees the storage allocated by .BR lc_keyring_init (). .PP .IR keyring is a pointer to the keyring to initialize. .PP .IR nkeys is the number of keys to allocate space for. .SH RETURN VALUE .BR lc_keyring_init () returns 0 if the call succeeds, or -1 if an error occurred. In the event of an error, .I errno is set to indicate the error. .SH ERRORS .BR lc_keyring_init () can fail with the following error: .TP .B ENOMEM Out of memory. Possibly, the application hit the .BR RLIMIT_AS or .BR RLIMIT_DATA limit described in .BR getrlimit (2). .SH SEE ALSO .BR lc_keyring_add (3), .BR lc_keyring_del (3), .BR lc_keyring_has (3), .BR lc_channel_filter_set (3), .BR lc_channel_new (3), .BR lc_keypair_new (3), .BR getrlimit (2) librecast/doc/lc_memsync.3000066400000000000000000000031701502456746400160260ustar00rootroot00000000000000.TH LC_MEMSYNC 3 2023-08-02 "LIBRECAST" "Librecast Programmer's Manual" .SH NAME lc_memsync \- synchronize two memory areas .SH LIBRARY Librecast library .RI ( liblibrecast ", " \-llibrecast ) .SH SYNOPSIS .nf .B #include .PP .BI "int lc_memsync(void " *dst ", void " *src ", const size_t " n ", q_t " *q " .BI " lc_stat_t " *stats ", lc_sync_options_t " *opt ", int " flags ");" .fi .PP Compile and link with \fI\-llibrecast\fP. .SH DESCRIPTION The .BR lc_memsync function synchronizes two non-overlapping memory areas of size .IR n bytes using merkle tree comparison, overwriting .IR dst with bytes from .IR src . .PP If .IR q is not NULL, it must point to a queue .IR q_t structure previously initialized with .BR q_init (3). This queue will have jobs enqueued to build the trees. This is normally used in conjunction with a threadpool created with .BR q_pool_create (3) with threads all calling .BR q_job_seek (3). .PP If .IR q is NULL, the creation and destruction of a queue and threadpool will be handled automatically. .PP If .IR stats is not NULL, transfer statistics will be returned in this structure. .PP .IR opt is not used, at present, and must be NULL for compatibility with future versions. .PP .IR flags is not used, at present, and must be zero for compatibility with future versions. .PP .SH RETURN VALUE .BR lc_memsync () returns zero on success. On error, \-1 is returned, and .I errno is set to indicate the error. .SH ERRORS .TP .BR EINVAL Invalid argument. .PP .BR ENOMEM Not enough space/cannot allocate memory (POSIX.1-2001). .PP .SH SEE ALSO .BR q_init (3), .BR q_free (3), .BR q_pool_create (3) librecast/doc/lc_mmapfile.3000066400000000000000000000032511502456746400161450ustar00rootroot00000000000000.TH LC_MMAPFILE 3 2023-07-24 "LIBRECAST" "Librecast Programmer's Manual" .SH NAME lc_mmapfile \- map or unmap files or devices into memory .SH LIBRARY Librecast library .RI ( liblibrecast ", " \-llibrecast ) .SH SYNOPSIS .nf .B #include .PP .BI "void *lc_mmapfile(const char " *pathname ", size_t " *len ", int " prot ", int " flags ", .BI " off_t " offset ", struct stat " *sb ");" .fi .PP Compile and link with \fI\-llibrecast\fP. .SH DESCRIPTION The .BR lc_mmapfile () function is a convenience wrapper for .BR mmap (2) which .BR open (2)s and maps a file in a single call. See .BR mmap (2) for a full description. .PP If .IR prot has the .BR PROT_WRITE flag set, .IR pathname is .BR open (2)'ed with the .BR O_RDWR and .BR O_CREAT flags set (the file is created and opened read-write), otherwise it is opened .BR O_RDONLY . The mode for the created file can be set by setting .IR st_mode in .IR sb when calling .BR lc_mmapfile (). .PP If .IR len points to a value greater than zero, .BR ftruncate (2) is called to truncate the file to the specified length. Otherwise, the variable .IR len points to is set to the size of the file. .PP When done, the file can be unmapped and the memory freed by calling .BR munmap (3). .PP .SH RETURN VALUE On success, .BR lc_mmapfile () returns a pointer to the mapped area. On error, the value .BR MAP_FAILED (that is, .IR (void *) -1 ) is returned, and .IR errno is set to indicate the error. .SH ERRORS .TP .BR ENODATA File is zero length. .PP See also .BR open (2), .BR mmap (2), .BR fstat (2), and .BR ftruncate (2). .PP .SH SEE ALSO .BR mmap (2), .BR msync (2), .BR munmap (2), .BR open (2), .BR fstat (2), .BR ftruncate (2) librecast/doc/lc_recv.3000066400000000000000000000041641502456746400153160ustar00rootroot00000000000000.TH LC_RECV 3 2025-06-09 "LIBRECAST" "Librecast Programmer's Manual" .SH NAME lc_recvtree, lc_recvchunk \- receive data over multicast .SH LIBRARY Librecast library .RI ( liblibrecast ", " \-llibrecast ) .SH SYNOPSIS .nf .B #include .PP .BI "ssize_t lc_recvtree(lc_ctx_t " *lctx ", unsigned char " *hash ", mtree_t " *tree "," .BI " lc_stat_t " *stats ", lc_sync_options_t " *opt ", int " flags ");" .BI "ssize_t lc_recvchunk(lc_ctx_t " *lctx ", unsigned char " *hash ", void " *data ", const size_t " len "," .BI " lc_stat_t " *stats ", lc_sync_options_t " *opt ", int " flags ");" .BI "ssize_t lc_recvdir(lc_ctx_t " *lctx ", unsigned char " *hash ", net_tree_t " **dir "," .BI " lc_stat_t " *stats ", lc_sync_options_t " *opt ", int " flags ");" .fi .PP Compile and link with \fI\-llibrecast\fP. .SH DESCRIPTION Each of these functions receives data over multicast by joining the librecast channel formed from the supplied .IR hash . .PP The .BR lc_recvtree function receives the merkle tree structure from channel .IR hash into .IR tree . .PP The .BR lc_recvchunk function receives a chunk of data of length .IR len (which can be fragmented over several packets) from channel .IR hash , writing it into the memory pointed to by .IR data . .PP The .BR lc_recvdir function is a wrapper for .BR lc_recvtree (3) which returns -1 and sets .IR errno to .BR ENOTDIR if the object received is not a directory. .PP If .IR stats is not NULL, transfer statistics will be returned in this structure. .PP .IR opt is not used, at present, and must be NULL for compatibility with future versions. .PP .IR flags is not used, at present, and must be zero for compatibility with future versions. .PP .SH RETURN VALUE These calls return the number of bytes received, or -1 if an error occurred. In the event of an error, .I errno is set to indicate the error. .SH ERRORS .TP .BR EINVAL Invalid argument. .PP .BR ENOMEM Not enough space/cannot allocate memory (POSIX.1-2001). .PP .BR ENOTDIR Not a directory. .PP .SH SEE ALSO .BR lc_ctx_new(3), .BR lc_share (3), .BR lc_sendtree (3), .BR lc_sendchunk (3) librecast/doc/lc_recvchunk.3000066400000000000000000000000231502456746400163350ustar00rootroot00000000000000.so man3/lc_recv.3 librecast/doc/lc_recvdir.3000066400000000000000000000000231502456746400160030ustar00rootroot00000000000000.so man3/lc_recv.3 librecast/doc/lc_recvtree.3000066400000000000000000000000231502456746400161640ustar00rootroot00000000000000.so man3/lc_recv.3 librecast/doc/lc_send.3000066400000000000000000000044031502456746400153040ustar00rootroot00000000000000.TH LC_SEND 3 2025-06-09 "LIBRECAST" "Librecast Programmer's Manual" .SH NAME lc_sendtree, lc_sendchunk \- send data over multicast .SH LIBRARY Librecast library .RI ( liblibrecast ", " \-llibrecast ) .SH SYNOPSIS .nf .B #include .PP .BI "ssize_t lc_sendtree(lc_ctx_t " *lctx ", unsigned char " *hash ", const mtree_t " *tree ", .BI " lc_stat_t " *stats ", lc_sync_options_t " *opt ", int " flags ");" .BI "ssize_t lc_sendchunk(lc_ctx_t " *lctx ", unsigned char " *hash ", const void " *data ", .BI " const size_t " len ", lc_stat_t " *stats ", lc_sync_options_t " *opt ", int " flags ");" .BI "ssize_t lc_senddir(lc_ctx_t " *lctx ", unsigned char " *hash ", net_tree_t " *dir ", .BI " lc_stat_t " *stats ", lc_sync_options_t " *opt ", int " flags ");" .fi .PP Compile and link with \fI\-llibrecast\fP. .SH DESCRIPTION Each of these functions sends data over multicast on the librecast channel formed from the supplied .IR hash . LCRQ (RaptorQ) encoding is used when sending. Trees, for which the length is not known by the receiver, include an OTI header (RaptorQ FEC Object Transmission Information header - see RFC 6330) with each packet. .PP Sending continues in a loop until the calling thread is cancelled. .PP The .BR lc_sendtree function sends the merkle tree structure .IR tree on channel .IR hash . The .BR lc_sendchunk function sends .IR len bytes of .IR data . .PP The .BR lc_senddir function is a wrapper for .BR lc_sendtree (3) which sends a directory object and adjusts the sending size to account for the directory data. .PP If .IR stats is not NULL, transfer statistics will be returned in this structure. .PP .IR opt is not used, at present, and must be NULL for compatibility with future versions. .PP The .I flags argument is the bitwise OR of zero of more of the following flags: .TP .BR LC_SHARE_LOOPBACK Set the loopback option .I IPV6_MULTICAST_LOOP on the sending socket. .SH RETURN VALUE These calls return the number of bytes received, or -1 if an error occurred. In the event of an error, .I errno is set to indicate the error. .SH ERRORS .TP .BR EINVAL Invalid argument. .PP .BR ENOMEM Not enough space/cannot allocate memory (POSIX.1-2001). .PP .SH SEE ALSO .BR lc_ctx_new(3), .BR lc_share (3), .BR lc_sendtree (3), .BR lc_sendchunk (3) librecast/doc/lc_sendchunk.3000066400000000000000000000000231502456746400163270ustar00rootroot00000000000000.so man3/lc_send.3 librecast/doc/lc_senddir.3000066400000000000000000000000231502456746400157750ustar00rootroot00000000000000.so man3/lc_send.3 librecast/doc/lc_sendtree.3000066400000000000000000000000231502456746400161560ustar00rootroot00000000000000.so man3/lc_send.3 librecast/doc/lc_share.3000066400000000000000000000064041502456746400154600ustar00rootroot00000000000000.TH LC_SHARE 3 2025-06-09 "LIBRECAST" "Librecast Programmer's Manual" .SH NAME lc_share, lc_unshare \- share and unshare files over multicast .SH LIBRARY Librecast library .RI ( liblibrecast ", " \-llibrecast ) .SH SYNOPSIS .nf .B #include .PP .BI "lc_share_t *lc_share(lc_ctx_t " *lctx ", mdex_t " *mdex ", unsigned int " ifx ", .BI " lc_stat_t " *stats ", lc_sync_options_t " *opt ", int " flags ");" .BI "void lc_unshare(lc_share_t " *share ");" .PP .BI "lc_share_t *lc_share_acquire(lc_share_t " *share ");" .BI "void lc_share_release(lc_share_t " *share ");" .fi .PP Compile and link with \fI\-llibrecast\fP. .SH DESCRIPTION The .BR lc_share function shares the objects indexed in .BR mdex on the interface given by .BR ifx . If ifx is zero, the files are shared on all multicast-capable interfaces. .PP .BR lc_share starts MLD snooping (see IETF RFC 3810). When a join on a new IPv6 multicast group is detected, this is checked against the index provided by .IR mdex . If a matching object is found, this is added to the sending queue, and the data for this object continues to be sent until MLD reports that there are no more listeners for this group. .PP The data sent is encoded using RaptorQ Forward Error Correction (see IETF RFC 6330), using the LCRQ library. .PP If .IR stats is not NULL, transfer statistics will be returned in this structure. .PP .IR opt is not used, at present, and must be NULL for compatibility with future versions. .PP The .I flags argument is the bitwise OR of zero of more of the following flags: .TP .BR LC_SHARE_LOOPBACK Set the loopback option .I IPV6_MULTICAST_LOOP on the sending socket. .PP The .BR lc_share_acquire function increments the reader count on the .IR share object. The object will not be freed until the reader count is zero. This is useful for keeping track of readers in a multithreaded program. .PP .BR lc_share_release decrements the reader count on the .IR share object. If the number of readers is zero, the object will be freed. .SH RETURN VALUE .BR lc_share () returns a pointer to a .IR lc_share_t handle, which should be freed by passing to .BR lc_unshare () when done. On error, NULL is returned, and .I errno is set to indicate the error. .PP The .BR lc_unshare () function returns no value, and preserves .IR errno . .SH ERRORS .TP .BR ENOTSUP .BR lc_share () is not supported with your current configuration. This error occurs when the librecast library is built without MLD support. .PP .BR ENOMEM Not enough space/cannot allocate memory (POSIX.1-2001). .PP .BR EACCES Permission to create a socket of the specified type and/or protocol is denied. .PP .SH NOTES .BR lc_share uses MLD snooping from libmld to detect which multicast groups are active, which uses a raw socket. On Linux, creating a raw socket requires .BR CAP_NET_RAW . See .BR Capabilities (7). On *BSD the creation of a raw socket is restricted to the superuser. An application can drop these privileges after calling .BR lc_share . .PP To restrict syncing to a particular network interface, call .BR lc_ctx_ifx (3) to set the default interface for the Librecast context before calling the appropriate sync function. .PP .SH SEE ALSO .BR lc_ctx_new (3), .BR lc_ctx_ifx (3), .BR mdex_init (3), .BR mdex_get (3), .BR mdex_put (3), .BR mdex_del (3), .BR lcrq (7) librecast/doc/lc_share_acquire.3000066400000000000000000000000241502456746400171610ustar00rootroot00000000000000.so man3/lc_share.3 librecast/doc/lc_share_release.3000066400000000000000000000000241502456746400171500ustar00rootroot00000000000000.so man3/lc_share.3 librecast/doc/lc_socket_close.3000066400000000000000000000000311502456746400170210ustar00rootroot00000000000000.so man3/lc_socket_new.3 librecast/doc/lc_socket_new.3000066400000000000000000000026021502456746400165130ustar00rootroot00000000000000.TH LC_SOCKET_NEW 3 2021-02-21 "LIBRECAST" "Librecast Programmer's Manual" .SH NAME lc_socket_new, lc_socket_close \- create and free Librecast sockets .SH LIBRARY Librecast library .RI ( liblibrecast ", " \-llibrecast ) .SH SYNOPSIS .nf .B #include .PP .BI "lc_socket_t *lc_socket_new(lc_ctx_t " "*ctx" ); .BI "void lc_socket_close(lc_socket_t " "*sock" ); .fi .PP Compile and link with \fI\-llibrecast\fP. .SH DESCRIPTION .BR lc_socket_new () creates a new Librecast socket. Call .BR lc_socket_close (3) when done. Sockets can also be freed by a call to .BR lc_ctx_free (3) on the Librecast context which will free the context and all associated sockets and channels. .PP .BR lc_socket_free () closes and frees a Librecast socket created with .BR lc_socket_new (3) . .SH RETURN VALUE .BR lc_socket_new () returns a pointer to a .I lc_socket_t handle. On error returns NULL and sets .I errno\fP. .BR .PP The .BR lc_socket_close () function returns no value. .SH ERRORS .BR lc_socket_new () can fail with the following errors: .TP .B ENOMEM Out of memory. Possibly, the application hit the .BR RLIMIT_AS or .BR RLIMIT_DATA limit described in .BR getrlimit (2). .PP .BR lc_socket_new () could also fail with any of the errors listed in .BR socket (2) or .BR setsockopt (2). .SH SEE ALSO .BR lc_channel_new (3), .BR lc_ctx_new (3), .BR lc_socket_setopt (3), .BR setsockopt (2), .BR socket (2) librecast/doc/lc_socketpair.3000066400000000000000000000023311502456746400165150ustar00rootroot00000000000000.TH LC_SOCKETPAIR 3 2024-04-08 "LIBRECAST" "Librecast Programmer's Manual" .SH NAME lc_socketpair \- create a pair of connected Librecast sockets .SH LIBRARY Librecast library .RI ( liblibrecast ", " \-llibrecast ) .SH SYNOPSIS .nf .B #include .PP .BI "int lc_socketpair(lc_ctx_t " *ctx ", lc_socket_t " *sock [2]); .fi .PP Compile and link with \fI\-llibrecast\fP. .SH DESCRIPTION .BR lc_socketpair () creates a pair of connected Librecast sockets. .PP Call .BR lc_socket_close (3) when done. Sockets can also be freed by a call to .BR lc_ctx_free (3) on the Librecast context which will free the context and all associated sockets and channels. .SH RETURN VALUE On success, zero is returned. On error, -1 is returned, .I errno is set to indicate the error. .SH ERRORS .BR lc_socketpair () can fail with the following errors: .TP .B ENOMEM Out of memory. Possibly, the application hit the .BR RLIMIT_AS or .BR RLIMIT_DATA limit described in .BR getrlimit (2). .PP .BR lc_socketpair () can also fail with any of the errors described in .BR socketpair (2). .PP .SH SEE ALSO .BR lc_socket_new (3), .BR lc_channel_new (3), .BR lc_ctx_new (3), .BR lc_socket_setopt (3), .BR setsockopt (2), .BR socket (2), .BR socketpair (2) librecast/doc/lc_sync.3000066400000000000000000000072341502456746400153340ustar00rootroot00000000000000.TH LC_SYNC 3 2025-06-09 "LIBRECAST" "Librecast Programmer's Manual" .SH NAME lc_sync, lc_syncfile \- synchronize memory or files over multicast .SH LIBRARY Librecast library .RI ( liblibrecast ", " \-llibrecast ) .SH SYNOPSIS .nf .B #include .PP .BI "ssize_t lc_sync(lc_ctx_t " *lctx ", unsigned char " *hash ", void " *data ", const size_t " len ", .BI " q_t " *q ", lc_stat_t " *stats ", lc_sync_options_t " *opt ", int " flags ");" .BI "ssize_t lc_syncfile(lc_ctx_t " *lctx ", unsigned char " *hash ", const char " *pathname ", .BI " q_t " *q ", lc_stat_t " *stats ", lc_sync_options_t " *opt ", int " flags ");" .BI "ssize_t lc_syncfilehash(lc_ctx_t " *lctx ", unsigned char " *hash ", const char " *dst ", .BI " q_t " *q ", lc_stat_t " *stats ", lc_sync_options_t " *opt ", int " flags ");" .fi .PP Compile and link with \fI\-llibrecast\fP. .SH DESCRIPTION The .BR lc_sync () function synchronizes the memory area pointed to by .IR data of length .IR len with data fetched from the network. .PP The .BR lc_syncfile () function synchronizes the file at .IR pathname with with data fetched from the network. The file will be created if it does not exist. .PP The .BR lc_syncfile_hash () function synchronizes the file at .IR pathname with with data fetched from the network. The file will be created if it does not exist. If a trailing slash is present it is parsed and removed before calling .BR lc_syncfile (3). Similar to .BR rsync (3), the presence of a trailing slash on the source directory indicates that the directories synced are at the same level. The absence of a trailing slash on the source will cause the directory to be created as a subdirectory on the destination. .PP .IR hash is used to create the multicast address from which to fetch the merkle tree of the source data. This tree is compared to the merkle tree of the memory at .IR data to find which chunks differ, and these chunks are fetched from the network using their hashes to create the multicast source addresses. .PP .IR lctx is a Librecast context, created with .BR lc_ctx_new (3). .PP If .IR q is not NULL, it must point to a queue .IR q_t structure previously initialized with .BR q_init (3). This queue will have jobs enqueued to build the tree. This is normally used in conjunction with a threadpool created with .BR q_pool_create (3) with threads all calling .BR q_job_seek (3). .PP If .IR q is NULL, the creation and destruction of a queue and threadpool will be handled automatically. .PP If .IR stats is not NULL, transfer statistics will be returned in this structure. .PP .IR opt is not used, at present, and must be NULL for compatibility with future versions. .PP .IR flags is not used, at present, and must be zero for compatibility with future versions. .PP .SH RETURN VALUE These calls return the number of bytes received, or -1 if an error occurred. On error, NULL is returned, and .I errno is set to indicate the error. .PP .SH ERRORS .TP .BR EINVAL Invalid argument. .PP .BR ENOMEM Not enough space/cannot allocate memory (POSIX.1-2001). .PP .BR EACCES Permission to create a socket of the specified type and/or protocol is denied. .PP .BR lc_syncfile () can also fail with any of the errors for .BR lc_mmapfile (3). .PP .SH NOTES To restrict syncing to a particular network interface, call .BR lc_ctx_ifx (3) to set the default interface for the Librecast context before calling the appropriate sync function. .PP .SH SEE ALSO .BR lc_ctx_new (3), .BR lc_ctx_ifx (3), .BR lc_mmapfile (3), .BR lc_share (3), .BR mdex_init (3), .BR mdex_free (3), .BR mdex_add (3), .BR mdex_addfile (3), .BR mdex_alias (3), .BR mdex_get (3), .BR mdex_put (3), .BR mdex_del (3), .BR lcrq (7) librecast/doc/lc_syncfile.3000066400000000000000000000000231502456746400161610ustar00rootroot00000000000000.so man3/lc_sync.3 librecast/doc/lc_syncfile_hash.3000066400000000000000000000000231502456746400171640ustar00rootroot00000000000000.so man3/lc_sync.3 librecast/doc/lc_syncfilelocal.3000066400000000000000000000037031502456746400172040ustar00rootroot00000000000000.TH LC_SYNCFILELOCAL 3 2023-08-22 "LIBRECAST" "Librecast Programmer's Manual" .SH NAME lc_syncfilelocal \- synchronize two local files .SH LIBRARY Librecast library .RI ( liblibrecast ", " \-llibrecast ) .SH SYNOPSIS .nf .B #include .PP .BI "int lc_syncfilelocal(const char " *dst ", const char " *src ", q_t " *q " .BI " lc_stat_t " *stats ", lc_sync_options_t " *opt ", int " flags ");" .fi .PP Compile and link with \fI\-llibrecast\fP. .SH DESCRIPTION The .BR lc_syncfilelocal () function synchronizes the file at .IR dst with the file at .IR src by overwriting .IR dst with bytes from .IR src . If .IR dst does not exist, it is created. .PP If .IR q is not NULL, it must point to a queue .IR q_t structure previously initialized with .BR q_init (3). This queue will have jobs enqueued to build the tree. This is normally used in conjunction with a threadpool created with .BR q_pool_create (3) with threads all calling .BR q_job_seek (3). .PP If .IR q is NULL, the creation and destruction of a queue and threadpool will be handled automatically. .PP If .IR stats is not NULL, transfer statistics will be returned in this structure. .PP .IR opt is not used, at present, and must be NULL for compatibility with future versions. .PP The .IR flags argument is the bitwise OR of zero of more of the following flags: .TP .BR MDEX_RECURSE recursively index directories. .PP .SH RETURN VALUE The .BR lc_syncfilelocal () function returns zero on success, or -1 if an error occurred. In the event of an error, .I errno is set to indicate the error. .SH ERRORS .TP .BR EINVAL Invalid argument. .PP .BR ENOMEM Not enough space/cannot allocate memory (POSIX.1-2001). .PP .BR lc_syncfilelocal () can also fail with any of the errors for .BR mmap (2) or .BR chmod (2). .PP .SH SEE ALSO .BR lc_memsync (3), .BR lc_sync (3), .BR lc_syncfile (3), .BR q_init (3), .BR q_free (3), .BR q_pool_create (3), .BR q_pool_destroy (3), .BR q_job_seek (3), .BR chmod (2), .BR mmap (2) librecast/doc/lc_token_new.3000066400000000000000000000032521502456746400163450ustar00rootroot00000000000000.TH LC_TOKEN_NEW 3 2025-04-02 "LIBRECAST" "Librecast Programmer's Manual" .SH NAME lc_token_new \- create and sign capability token .SH LIBRARY Librecast library .RI ( liblibrecast ", " \-llibrecast ) .SH SYNOPSIS .nf .B #include .PP .BI "int lc_token_new(lc_token_t " *token ", lc_keypair_t " *signing_key ", uint8_t " *bearer_key "," .BI lc_channel_t " *chan ", uint8_t " capbits ", uint64_t " valid_sec"); .fi .PP Compile and link with \fI\-llibrecast\fP. .SH DESCRIPTION .BR lc_token_new () creates and signs a new capability token. .PP .IR token is a pointer to the token to sign. .PP .IR signing_key is a pointer to the signing keypair, created with .BR lc_keypair_new (3). .PP .IR bearer_key is a pointer to the public key of the bearer of the token. The bearer is the entity using the token for sending. .PP .IR chan is a pointer to the Librecast channel for which the token will be valid. .PP .IR capbits is an 8-bit arbitrary value representing the capabilities to issue. These have no intrinsic meaning and are defined by the caller. .PP .IR valid_sec is an unsigned 64-bit value representing the number of seconds from now that the token will be valid for. .SH RETURN VALUE .BR lc_socket_new () returns 0 if the call succeeds, or -1 if an error occurred. In the event of an error, .I errno is set to indicate the error. .SH ERRORS .BR lc_token_new () can fail with the following errors: .TP .B ENOTRECOVERABLE Signing the token failed. .PP .BR lc_token_new () could also fail with any of the errors listed in .BR clock_gettime (2) .SH SEE ALSO .BR lc_channel_token_set (3), .BR lc_channel_filter_set (3), .BR lc_channel_new (3), .BR lc_keypair_new (3), .BR clock_gettime (2) librecast/doc/lc_tuntap_create.3000066400000000000000000000015731502456746400172160ustar00rootroot00000000000000.TH LC_TUNTAP_CREATE 3 2022-02-01 "LIBRECAST" "Librecast Programmer's Manual" .SH NAME lc_tuntap_create \- create TUN/TAP devices .SH LIBRARY Librecast library .RI ( liblibrecast ", " \-llibrecast ) .SH SYNOPSIS .nf .B #include .PP .BI "int lc_tuntap_create(char *" ifname ", int " flags ); .fi .PP Compile and link with \fI\-llibrecast\fP. .PP The \fIflags\fP argument may contain the following flags. One of IFF_TUN or IFF_TAP is required. .TP .B IFF_TUN create TUN device (no Ethernet headers) .TP .B IFF_TAP create TAP device .TP .B IFF_NO_PI Do not provide packet information. .TP .B IFF_MULTI_QUEUE Create a queue of multiqueue device. .SH DESCRIPTION .BR lc_tuntap_create () creates a new TUN/TAP device . .SH RETURN VALUE .BR lc_socket_new () On success, a file descriptor for the new socket is returned. On error, -1 is returned, and errno is set appropriately. librecast/doc/lc_unshare.3000066400000000000000000000000241502456746400160130ustar00rootroot00000000000000.so man3/lc_share.3 librecast/doc/librecast.7000066400000000000000000000042261502456746400156540ustar00rootroot00000000000000.TH librecast 7 2025-05-18 Librecast "Librecast Programmer's Manual" .SH NAME librecast - C multicast library .SH DESCRIPTION Librecast is a C multicast library which aims to make working with multicast easier. .PP Librecast extends IPv6 multicast to provide a multicast communication layer with support for encodings, encryption, file syncing, router topologies and overlay multicast. .SS Librecast Objects The Librecast C API has a number of basic objects, which are used throughout Librecast, such as Contexts, Sockets, Channels, and Routers. .TP .B Context (\fIlc_ctx_t\fR) A Librecast Context is the root object to which all other objects are linked. It is required for creating Sockets, Channels, Routers and for calling many API functions. Default settings for other objects, such as sending rate limits, can be set on the Context, and overridden when other objects are created. It is not necessary to individually free Sockets, Channels or Routers. A single call to .BR lc_ctx_free (3) will free all associated objects. .TP .B Socket (\fIlc_socket_t\fR) Librecast Sockets are endpoints for multicast communication and can be bound to one or more Librecast Channels. Sockets can be IPv6 or socketpair. Support for Websocket and WebRTC Sockets is planned for an upcoming release. .TP .B Channel (\fIlc_channel_t\fR) A Librecast Channel is an analogue for a multicast group with settings, such as encodings (eg. encryption, RaptorQ FEC), rate-limits etc. applied. A Channel must be bound to a Socket before it can be used. .TP .B Router (\fIlc_router_t\fR) The Router API adds a number of function calls to the Librecast C Library for creating and managing an in-memory multicast router. This forms the basis of several other APIs, such as the Websocket API, WebRTC API and allows for network simulations and measurements. .PP .SH BUGS If you find one, email \fIbugs@librecast.net\fR or raise an issue in our bug tracker at \fIhttps://bugs.librecast.net/\fR. .SH SEE ALSO The Librecast website has more information: \fIhttps://librecast.net/\fR .BR lc_ctx_new (3), .BR lc_socket_new (3), .BR lc_socketpair (3), .BR lc_channel_new (3), .BR lc_share (3), .BR lc_mdex_init (3), .BR lcrq (7) librecast/doc/mdex_add.3000066400000000000000000000046261502456746400154510ustar00rootroot00000000000000.TH MDEX_ADD 3 2023-06-20 "LIBRECAST" "Librecast Programmer's Manual" .SH NAME mdex_add, mdex_addfile, mdex_alias \- index data, files and directories .SH LIBRARY Librecast library .RI ( liblibrecast ", " \-llibrecast ) .SH SYNOPSIS .nf .B #include .PP .BI "int mdex_add(mdex_t " *mdex ", void " *data ", size_t " len ", q_t " *q ", int " flags ");" .BI "int mdex_addfile(mdex_t " *mdex ", const char " *path ", q_t " *q ", int " flags ");" .BI "int mdex_alias(mdex_t " *mdex ", unsigned char " *alias ", size_t " aliaslen ", .BI " unsigned char " *hash ", size_t " hashlen ");" .fi .PP Compile and link with \fI\-llibrecast\fP. .SH DESCRIPTION The .BR mdex_add function builds a merkle tree from .IR data with length .IR len and adds entries for both the tree and chunks to .IR mdex . .PP The .BR mdex_addfile function builds a merkle tree from the file or directory at .IR path and adds entries for the trees and chunks to .IR mdex . .PP The .BR mdex_alias function adds an entry .IR alias of length .IR aliaslen which points to the entry .IR hash of length .IR hashlen which must already exist in .IR mdex . .PP If .IR q is not NULL, it must point to a queue .IR q_t structure previously initialized with .BR q_init (3). This will be passed through to .BR mtree_build (3) to build the merkle tree. This is normally used in conjunction with a threadpool created with .BR q_pool_create (3) with threads all calling .BR q_job_seek (3). .PP The .I flags argument is the bitwise OR of zero of more of the following flags: .TP .BR MDEX_ALIAS Entry is a pointer to another entry. .PP .BR MDEX_RAND Entry should be sent using random symbols. .PP .BR MDEX_RECURSE Recursively index all files and directories below .IR path . (mdex_addfile) .PP .BR MDEX_MOUNT If set, stay within the same filesystem (i.e., do not cross mount points). .TP .BR MDEX_SYMLINK Follow symbolic links when recursively indexing. .PP .SH RETURN VALUE These function return zero on success. On error, \-1 is returned, and .I errno is set to indicate the error. .SH ERRORS .TP .BR EINVAL Invalid argument. Both .IR mdex and .IR hash are required (not NULL), and .IR hashlen > 0. .PP .BR ENOMEM Not enough space/cannot allocate memory (POSIX.1-2001). .PP .SH SEE ALSO .BR mdex_init (3), .BR mdex_free (3), .BR mdex_get (3), .BR mdex_put (3), .BR mdex_del (3), .BR mtree_build (3), .BR q_init (3), .BR q_pool_create (3), .BR q_job_seek (3) .BR lc_share (3) librecast/doc/mdex_addfile.3000066400000000000000000000000241502456746400162750ustar00rootroot00000000000000.so man3/mdex_add.3 librecast/doc/mdex_alias.3000066400000000000000000000000241502456746400157760ustar00rootroot00000000000000.so man3/mdex_add.3 librecast/doc/mdex_basedir.3000066400000000000000000000014261502456746400163250ustar00rootroot00000000000000.TH MDEX_BASEDIR 3 2023-07-23 "LIBRECAST" "Librecast Programmer's Manual" .SH NAME mdex_basedir \- set base directory for multicast index .SH LIBRARY Librecast library .RI ( liblibrecast ", " \-llibrecast ) .SH SYNOPSIS .nf .B #include .PP .BI "void mdex_basedir(mdex_t " *mdex ", char " *basedir ");" .fi .PP Compile and link with \fI\-llibrecast\fP. .SH DESCRIPTION The .BR mdex_basedir function sets the base directory for .IR mdex to .IR basedir . This will be stripped from the the beginning of all files added to the index with .BR mdex_addfile (3). .PP .SH RETURN VALUE The .BR mdex_basedir () function returns no value. .SH ERRORS None. .PP .SH SEE ALSO .BR mdex_init (3), .BR mdex_free (3), .BR mdex_get (3), .BR mdex_put (3), .BR mdex_del (3), .BR lc_share (3) librecast/doc/mdex_del.3000066400000000000000000000025011502456746400154530ustar00rootroot00000000000000.TH MDEX_DEL 3 2023-06-20 "LIBRECAST" "Librecast Programmer's Manual" .SH NAME mdex_del \- delete an entry from a multicast index .SH LIBRARY Librecast library .RI ( liblibrecast ", " \-llibrecast ) .SH SYNOPSIS .nf .B #include .PP .BI "int mdex_del(mdex_t " *mdex ", unsigned char " *hash ", size_t " hashlen ");" .fi .PP Compile and link with \fI\-llibrecast\fP. .SH DESCRIPTION The .BR mdex_del function deletes an entry from the multicast index .IR mdex using .IR hash (of length .IR hashlen ) as the key. If no matching entry is found in the index, -1 is returned and errno is set to .BR ENOENT . .PP .IR hashlen can be shorter than the full length of the hash stored with .BR mdex_put (3) and will delete the first entry matching the truncated hash. This allows us to store the full 32 byte hash in the index, but still match against the truncated hash derived from, say, the 14 bytes of an IPv6 multicast group address. .SH RETURN VALUE .BR mdex_put () returns zero on success. On error, \-1 is returned, and .I errno is set to indicate the error. .SH ERRORS .TP .BR EINVAL Invalid argument. Both .IR mdex and .IR hash are required (not NULL), and .IR hashlen > 0. .PP .BR ENOENT No entry found matching .IR hash . .SH SEE ALSO .BR mdex_init (3), .BR mdex_free (3), .BR mdex_get (3), .BR mdex_put (3), .BR lc_share (3) librecast/doc/mdex_free.3000066400000000000000000000000251502456746400156270ustar00rootroot00000000000000.so man3/mdex_init.3 librecast/doc/mdex_get.3000066400000000000000000000034661502456746400155010ustar00rootroot00000000000000.TH MDEX_GET 3 2023-06-20 "LIBRECAST" "Librecast Programmer's Manual" .SH NAME mdex_get \- retrieve an entry from a multicast index .SH LIBRARY Librecast library .RI ( liblibrecast ", " \-llibrecast ) .SH SYNOPSIS .nf .B #include .PP .BI "int mdex_get(mdex_t " *mdex ", unsigned char " *hash ", size_t " hashlen ", mdex_entry_t " *entry ");" .BI "int mdex_getalias(mdex_t " *mdex ", const char " *path ", mdex_entry_t " *entry ");" .fi .PP Compile and link with \fI\-llibrecast\fP. .SH DESCRIPTION The .BR mdex_get function retrieves an entry from the multicast index .IR mdex using .IR hash (of length .IR hashlen ) as the key, and returns a copy of the data in .IR entry if provided. If .IR entry is NULL, the return value can be used to check if an entry exists in the index without retrieving it. .PP If no matching entry is found in the index, -1 is returned and errno is set to .BR ENOENT . .PP .IR hashlen can be shorter than the full length of the hash stored with .BR mdex_put (3) and will return the first entry matching the truncated hash. This allows us to store the full 32 byte hash in the index, but still match against the truncated hash derived from, say, the 14 bytes of an IPv6 multicast group address. .PP The .BR mdex_getalias() function is a wrapper which calls .BR mdex_get() with the hash of the NUL-terminated string .IR path , returning the result. .SH RETURN VALUE .BR mdex_get () returns zero on success. On error, \-1 is returned, and .I errno is set to indicate the error. .SH ERRORS .TP .BR EINVAL Invalid argument. Both .IR mdex and .IR hash are required (not NULL), and .IR hashlen > 0. .PP .BR ENOENT No entry found matching .IR hash . .TP .BR ELOOP Infinite loop. Alias points to itself. .SH SEE ALSO .BR mdex_init (3), .BR mdex_free (3), .BR mdex_put (3), .BR mdex_del (3), .BR lc_share (3) librecast/doc/mdex_getalias.3000066400000000000000000000000241502456746400164760ustar00rootroot00000000000000.so man3/mdex_get.3 librecast/doc/mdex_init.3000066400000000000000000000020611502456746400156530ustar00rootroot00000000000000.TH MDEX_INIT 3 2023-06-20 "LIBRECAST" "Librecast Programmer's Manual" .SH NAME mdex_init, mtree_free \- initialize and free a multicast index .SH LIBRARY Librecast library .RI ( liblibrecast ", " \-llibrecast ) .SH SYNOPSIS .nf .B #include .PP .BI "mdex_t *mdex_init(size_t " entries ");" .BI "void mdex_free(mdex_t " *mdex ");" .fi .PP Compile and link with \fI\-llibrecast\fP. .SH DESCRIPTION The .BR mdex_init function initializes a multicast index. .PP .IR entries gives the initial number of entries to allocate. This is just a hint for initial memory allocation, and the index will be resized as required. .SH RETURN VALUE .BR mdex_init () returns a pointer to a .IR mdex_t handle, which should be freed by passing to .BR mdex_free () when done. On error, NULL is returned, and .I errno is set to indicate the error. .PP The .BR mdex_free () function returns no value, and preserves .IR errno . .SH ERRORS .TP .BR ENOMEM Not enough space/cannot allocate memory (POSIX.1-2001). .PP .SH SEE ALSO .BR mdex_get (3), .BR mdex_put (3), .BR mdex_del (3) librecast/doc/mdex_put.3000066400000000000000000000020361502456746400155220ustar00rootroot00000000000000.TH MDEX_PUT 3 2023-06-20 "LIBRECAST" "Librecast Programmer's Manual" .SH NAME mdex_put \- insert an entry into a multicast index .SH LIBRARY Librecast library .RI ( liblibrecast ", " \-llibrecast ) .SH SYNOPSIS .nf .B #include .PP .BI "int mdex_put(mdex_t " *mdex ", unsigned char " *hash ", size_t " hashlen ", mdex_entry_t " *entry ");" .fi .PP Compile and link with \fI\-llibrecast\fP. .SH DESCRIPTION The .BR mdex_put function stores the value of .IR entry in the multicast index .IR mdex , using .IR hash (of length .IR hashlen ) as the key. .PP .IR entry may be NULL, and an entry will still be created. .SH RETURN VALUE .BR mdex_put () returns zero on success. On error, \-1 is returned, and .I errno is set to indicate the error. .SH ERRORS .TP .BR EINVAL Invalid argument. Both .IR mdex and .IR hash are required (not NULL), and .IR hashlen > 0. .PP .BR ENOMEM Not enough space/cannot allocate memory (POSIX.1-2001). .PP .SH SEE ALSO .BR mdex_init (3), .BR mdex_free (3), .BR mdex_get (3), .BR mdex_del (3), .BR lc_share (3) librecast/doc/mdex_tree_hash.3000066400000000000000000000016331502456746400166560ustar00rootroot00000000000000.TH MDEX_TREE_HASH 3 2023-07-23 "LIBRECAST" "Librecast Programmer's Manual" .SH NAME mdex_tree_hash \- create hash of merkle tree root .SH LIBRARY Librecast library .RI ( liblibrecast ", " \-llibrecast ) .SH SYNOPSIS .nf .B #include .PP .BI "int mdex_tree_hash(unsigned char " *hash ", size_t " hashlen ", mtree_t " *mtree ", size_t " n ");" .fi .PP Compile and link with \fI\-llibrecast\fP. .SH DESCRIPTION The .BR mdex_tree_hash function creates a .IR hash of length .IR hashlen from the root node of .IR mtree with key .IR n . This is used to index an mtree in several parts, and to distinguish the root node from the first data node when nodes = 1. .PP .SH RETURN VALUE The .BR mdex_tree_hash () returns zero on success. On error, \-1 is returned. .PP .SH SEE ALSO .BR hash_generic_key (3), .BR mdex_init (3), .BR mdex_free (3), .BR mdex_get (3), .BR mdex_put (3), .BR mdex_del (3), .BR lc_share (3) librecast/doc/mtree_build.3000066400000000000000000000025031502456746400161670ustar00rootroot00000000000000.TH MTREE_BUILD 3 2023-06-20 "LIBRECAST" "Librecast Programmer's Manual" .SH NAME mtree_build \- build a merkle tree from base data .SH LIBRARY Librecast library .RI ( liblibrecast ", " \-llibrecast ) .SH SYNOPSIS .nf .B #include .PP .BI "int mtree_build(mtree_t " *tree ", void * const " data ", q_t " *q ");" .fi .PP Compile and link with \fI\-llibrecast\fP. .SH DESCRIPTION The .BR mtree_build function builds a merkle tree .IR tree which was previously initialized with .BR mtree_init (3) from the base data pointed to by .IR data . .PP If .IR q is not NULL, it must point to a queue .IR q_t structure previously initialized with .BR q_init (3). This queue will have jobs enqueued to build the tree. This is normally used in conjunction with a threadpool created with .BR q_pool_create (3) with threads all calling .BR q_job_seek (3). .PP If .IR q is NULL, the creation and destruction of a queue and threadpool will be handled automatically. .SH RETURN VALUE .BR mtree_init () returns zero on success. On error, -1 is returned, and .I errno is set to indicate the error. .PP The .BR mtree_free () function returns no value, and preserves .IR errno . .SH ERRORS TODO .SH BUGS No error handling. .SH EXAMPLE TODO .SH SEE ALSO .BR mtree_init (3), .BR mtree_free (3), .BR q_init (3), .BR q_pool_create (3), .BR q_job_seek (3) librecast/doc/mtree_child.3000066400000000000000000000013121502456746400161500ustar00rootroot00000000000000.TH MTREE_CHILD 3 2023-07-23 "LIBRECAST" "Librecast Programmer's Manual" .SH NAME mtree_child \- return node number of first child node .SH LIBRARY Librecast library .RI ( liblibrecast ", " \-llibrecast ) .SH SYNOPSIS .nf .B #include .PP .BI "size_t mtree_child(mtree_t " *tree ", size_t " node ");" .fi .PP Compile and link with \fI\-llibrecast\fP. .SH DESCRIPTION The .BR mtree_nnode function returns the node number of the first child of .IR node in .IR tree . .PP Nodes are numbered from 0 = root. .SH RETURN VALUE .BR mtree_child () returns the number of the first child node, or 0 if none. .PP .SH ERRORS None. .PP .SH SEE ALSO .BR mtree_init (3), .BR mtree_free (3), .BR mtree_build (3) librecast/doc/mtree_diff_map.3000066400000000000000000000000361502456746400166340ustar00rootroot00000000000000.so man3/mtree_diff_subtree.3 librecast/doc/mtree_diff_subtree.3000066400000000000000000000032421502456746400175320ustar00rootroot00000000000000.TH MTREE_DIFF_SUBTREE 3 2023-06-20 "LIBRECAST" "Librecast Programmer's Manual" .SH NAME mtree_diff_subtree \- compare two subtrees and return bitmap .SH LIBRARY Librecast library .RI ( liblibrecast ", " \-llibrecast ) .SH SYNOPSIS .nf .B #include .PP .BI "unsigned char *mtree_diff_subtree(mtree_t " *t1 ", mtree_t " *t2 ", size_t " root ", unsigned " bits ");" .BI "unsigned char *mtree_diff_map(mtree_t " *t1 ", mtree_t " *t2 ");" .fi .PP Compile and link with \fI\-llibrecast\fP. .SH DESCRIPTION The .BR mtree_diff_subtree function performs a bredth-first comparison of the merkle trees .IR t1 and .IR t2 and returns a pointer to a bitmap, setting .IR bits bits for any chunks that differ. .IR bits should be set to the number of packets required to to transport each chunk. When bits > 1, chunks will be fragmented into multiple packets, and the bitmap will represent the packets required. .PP Checking the popcount (Hamming Weight) of the returned bitmap gives the number of packets required to patch the differences. .PP The returned bitmap must be freed by the caller when no longer needed by passing to .BR free (3). .PP .BR mtree_diff_map () is a convenience wrapper that is the same as calling .BR mtree_diff_subtree () with .IR root set to zero (whole tree) and .IR bits set to one. Thus, it returns a bitmap of the entire tree with a single bit per chunk. .PP .SH RETURN VALUE .BR mtree_verify () returns zero if the tree is valid, or NULL on error, with .IR errno set to indicate the error. .SH ERRORS .TP .BR ENOMEM Not enough space/cannot allocate memory (POSIX.1-2001). .PP .SH SEE ALSO .BR mtree_init (3), .BR mtree_free (3), .BR mtree_build (3), .BR free (3) librecast/doc/mtree_free.3000066400000000000000000000000261502456746400160070ustar00rootroot00000000000000.so man3/mtree_init.3 librecast/doc/mtree_init.3000066400000000000000000000017601502456746400160370ustar00rootroot00000000000000.TH MTREE_INIT 3 2023-06-20 "LIBRECAST" "Librecast Programmer's Manual" .SH NAME mtree_init, mtree_free \- initialize and free a merkle tree .SH LIBRARY Librecast library .RI ( liblibrecast ", " \-llibrecast ) .SH SYNOPSIS .nf .B #include .PP .BI "int mtree_init(mtree_t " *tree ", size_t " sz ");" .BI "void mtree_free(mtree_t " *tree ");" .fi .PP Compile and link with \fI\-llibrecast\fP. .SH DESCRIPTION The .BR tree_init function initializes the merkle tree structure .IR tree with base data size .IR sz . sz is the size in bytes of the base file or data which will be used to build the tree by calling .BR mtree_build (3). .SH RETURN VALUE .BR mtree_init () returns zero on success. On error, -1 is returned, and .I errno is set to indicate the error. .PP The .BR mtree_free () function returns no value, and preserves .IR errno . .SH ERRORS .TP .BR ENOMEM Not enough space/cannot allocate memory (POSIX.1-2001). .PP .SH SEE ALSO .BR mdex_get (3), .BR mdex_put (3), .BR mdex_del (3) librecast/doc/mtree_nnode.3000066400000000000000000000014301502456746400161710ustar00rootroot00000000000000.TH MTREE_NNODE 3 2023-06-20 "LIBRECAST" "Librecast Programmer's Manual" .SH NAME mtree_nnode \- return pointer to mtree node .SH LIBRARY Librecast library .RI ( liblibrecast ", " \-llibrecast ) .SH SYNOPSIS .nf .B #include .PP .BI "uint8_t *mtree_nnode(mtree_t " *tree ", size_t " node ");" .fi .PP Compile and link with \fI\-llibrecast\fP. .SH DESCRIPTION The .BR mtree_nnode function returns a pointer to the hash of node .IR node , where 0 = root. .SH RETURN VALUE .BR mtree_nnode () returns a pointer to the hash of the numbered node. On error, NULL is returned, and .I errno is set to indicate the error. .PP .SH ERRORS .TP .BR ERANGE The .IR node requested is out of range for .IR tree . .PP .SH SEE ALSO .BR mtree_init (3), .BR mtree_free (3), .BR mtree_build (3) librecast/doc/mtree_parent.3000066400000000000000000000013661502456746400163670ustar00rootroot00000000000000.TH MTREE_PARENT 3 2023-07-23 "LIBRECAST" "Librecast Programmer's Manual" .SH NAME mtree_parent \- return node number of parent node .SH LIBRARY Librecast library .RI ( liblibrecast ", " \-llibrecast ) .SH SYNOPSIS .nf .B #include .PP .BI "size_t mtree_parent(size_t " node ");" .fi .PP Compile and link with \fI\-llibrecast\fP. .SH DESCRIPTION The .BR mtree_nnode function returns the node number of the parent of .IR node. .PP This calculation is independent of the tree, and is implemented as a macro. .PP Nodes are numbered from 0 = root. .SH RETURN VALUE .BR mtree_parent () returns the number of the parent node. .PP .SH ERRORS None. .PP .SH SEE ALSO .BR mtree_init (3), .BR mtree_free (3), .BR mtree_build (3), .BR mtree_child (3) librecast/doc/mtree_subtree_data_max.3000066400000000000000000000000421502456746400203730ustar00rootroot00000000000000.so man3/mtree_subtree_data_min.3 librecast/doc/mtree_subtree_data_min.3000066400000000000000000000017411502456746400204000ustar00rootroot00000000000000.TH MTREE_SUBTREE_DATA 3 2023-07-23 "LIBRECAST" "Librecast Programmer's Manual" .SH NAME mtree_subtree_data_min, mtree_subtree_data_max \- return min\/max data nodes .SH LIBRARY Librecast library .RI ( liblibrecast ", " \-llibrecast ) .SH SYNOPSIS .nf .B #include .PP .BI "size_t mtree_subtree_data_min(size_t " base ", size_t " root ");" .BI "size_t mtree_subtree_data_max(size_t " base ", size_t " root ");" .fi .PP Compile and link with \fI\-llibrecast\fP. .SH DESCRIPTION The .BR mtree_subtree_data_min and .BR mtree_subtree_data_max functions return the node number of the minimum and maximum data nodes respectively for the subtree with root node .IR root for a tree with .IR base data nodes. .PP Nodes are numbered from 0 = root. .SH RETURN VALUE These functions return the number of the min or max data node as appropriate. .PP .SH ERRORS None. .PP .SH SEE ALSO .BR mtree_init (3), .BR mtree_free (3), .BR mtree_build (3), .BR mtree_child (3), .BR mtree_parent (3) librecast/doc/mtree_verify.3000066400000000000000000000012621502456746400163750ustar00rootroot00000000000000.TH MTREE_VERIFY 3 2023-06-20 "LIBRECAST" "Librecast Programmer's Manual" .SH NAME mtree_verify \- validate a merkle tree .SH LIBRARY Librecast library .RI ( liblibrecast ", " \-llibrecast ) .SH SYNOPSIS .nf .B #include .PP .BI "int mtree_verify(mtree_t " *tree ");" .fi .PP Compile and link with \fI\-llibrecast\fP. .SH DESCRIPTION The .BR mtree_verify function re-hashes the nodes in .IR tree from the base to the root, returning zero if the tree is valid. .SH RETURN VALUE .BR mtree_verify () returns zero if the tree is valid, -1 if not. .SH ERRORS None. .SH SEE ALSO .BR mtree_init (3), .BR mtree_free (3), .BR q_init (3), .BR q_pool_create (3), .BR q_job_seek (3) librecast/doc/q_free.3000066400000000000000000000000221502456746400151270ustar00rootroot00000000000000.so man3/q_init.3 librecast/doc/q_init.3000066400000000000000000000020141502456746400151540ustar00rootroot00000000000000.TH Q_INIT 3 2023-07-23 "LIBRECAST" "Librecast Programmer's Manual" .SH NAME q_init, q_free \- initialize and free queue .SH LIBRARY Librecast library .RI ( liblibrecast ", " \-llibrecast ) .SH SYNOPSIS .nf .B #include .PP .BI "int q_init(q_t " *q ");" .BI "int q_free(q_t " *q ");" .fi .PP Compile and link with \fI\-llibrecast\fP. .SH DESCRIPTION The .BR q_init () function initializes smolq queue .IR q . .PP You will be surprised to learn that .BR q_free () is the corresponding function to free a queue so initialized. .PP .SH RETURN VALUE These functions return zero on success. On error, -1 is returned and .IR errno is set to indicate the error. .PP .SH ERRORS .BR q_init () may fail when initializing the queue semaphore. .BR q_free () may fail when destroying the queue semaphore. See .BR sem_init (3) and .BR sem_destroy (3) for the relevant error codes. .PP .SH SEE ALSO .BR q_job_seek (3), .BR q_pool_create (3), .BR q_pool_destroy (3), .BR q_push (3), .BR q_wait (3), .BR sem_init (3), .BR sem_destroy (3) librecast/doc/q_job_seek.3000066400000000000000000000020561502456746400160000ustar00rootroot00000000000000.TH Q_JOB_SEEK 3 2023-07-23 "LIBRECAST" "Librecast Programmer's Manual" .SH NAME q_job_seek \- wait for and execute jobs from a smolq queue .SH LIBRARY Librecast library .RI ( liblibrecast ", " \-llibrecast ) .SH SYNOPSIS .nf .B #include .PP .BI "void *q_job_seek(void " *arg ");" .fi .PP Compile and link with \fI\-llibrecast\fP. .SH DESCRIPTION The .BR q_job_seek () function atomically fetches the next .IR job in .IR q and executes it before looping and repeating. This is intended to be used as the start_routine for .BR pthread_create (3) or used as the function .IR f when calling .BR q_pool_create (3). .PP The function loops indefinitely until the thread is cancelled with .BR pthread_cancel (3) or .BR q_pool_destroy (3). .PP .SH RETURN VALUE The .BR q_job_seek () function returns the same pointer .IR arg that was passed to it. .PP .SH ERRORS None. .PP .SH SEE ALSO .BR q_pool_create (3), .BR q_pool_destroy (3), .BR q_init (3), .BR q_free (3), .BR q_push (3), .BR q_wait (3), .BR sem_wait (3), .BR pthread_cancel (3), .BR pthread_create (3) librecast/doc/q_pool_create.3000066400000000000000000000032631502456746400165140ustar00rootroot00000000000000.TH Q_POOL_CREATE 3 2023-07-23 "LIBRECAST" "Librecast Programmer's Manual" .SH NAME q_pool_create, q_pool_destroy \- initialize and destroy thread pools .SH LIBRARY Librecast library .RI ( liblibrecast ", " \-llibrecast ) .SH SYNOPSIS .nf .B #include .PP .BI "int q_pool_create(pthread_t " tid[] ", int " nthreads ", void *(*" f ")(void *), void *restrict " arg ");" .BI "int q_pool_destroy(pthread_t " tid[] ", int " nthreads ");" .fi .PP Compile and link with \fI\-llibrecast\fP. .SH DESCRIPTION The .BR q_pool_create () function creates a thread pool of .IR nthreads threads, using .IR f and .IR arg as the start_routine and argument for each thread. .PP .BR q_pool_create () is designed for use with .BR q_job_seek (3) to start a thread pool of workers to process jobs from a smolq queue. .PP The .BR q_pool_destroy () function is called to cancel and reap the threads created with .BR q_pool_create (3). .PP .IR tid must be an array of pthread_t of size .IR nthreads . .PP .SH RETURN VALUE These functions return zero on success. On error, the number of threads that failed to start or stop is returned and .IR errno is set to indicate the error. .PP If .BR q_pool_create () successfully starts any threads, these are not cancelled if there is a failure starting a later thread. Call .BR q_pool_destroy (3) to destroy the created threads when done, passing .IR nthreads minus the return value from the failed call to .BR q_pool_create () to stop the running threads. .PP .SH ERRORS .BR q_pool_create () may fail with any of the errors for .BR pthread_create (3). .PP .SH SEE ALSO .BR q_job_seek (3), .BR q_push (3), .BR q_wait (3), .BR sem_init (3), .BR sem_destroy (3), .BR pthread_create (3) librecast/doc/q_pool_destroy.3000066400000000000000000000000311502456746400167300ustar00rootroot00000000000000.so man3/q_pool_create.3 librecast/doc/q_push.3000066400000000000000000000023631502456746400151770ustar00rootroot00000000000000.TH Q_PUSH 3 2023-07-25 "LIBRECAST" "Librecast Programmer's Manual" .SH NAME q_push \- push a job onto a smolq queue .SH LIBRARY Librecast library .RI ( liblibrecast ", " \-llibrecast ) .SH SYNOPSIS .nf .B #include .PP .BI "int q_push(q_t " *q ", void *(*" f ")(void *), void *restrict " arg ");" .BI "int q_trypush(q_t " *q ", void *(*" f ")(void *), void *restrict " arg ");" .fi .PP Compile and link with \fI\-llibrecast\fP. .SH DESCRIPTION .BR q_push () pushes .IR f onto the queue .IR q with argument .IR arg. .PP .BR q_trypush () is the same as .BR q_push () except that if the queue writer lock cannot be immediately obtained, then the call returns an error .RI ( errno set to .BR EAGAIN ) instead of blocking. .PP .SH RETURN VALUE The .BR q_push () function returns zero on success. On error, -1 is returned and .IR errno is set to indicate the error. .PP .SH ERRORS .TP .BR EAGAIN ( .BR q_trypush ()) The operation could not be performed without blocking. (i.e., the queue was full). .PP The function can also fail with the errors for .BR sem_post (3) or .BR sem_wait (3). .PP .SH SEE ALSO .BR q_job_seek (3), .BR q_pool_create (3), .BR q_pool_destroy (3), .BR q_init (3), .BR q_free (3), .BR q_wait (3), .BR sem_post (3), .BR sem_wait (3) librecast/doc/q_search.3000066400000000000000000000023461502456746400154660ustar00rootroot00000000000000.TH Q_SEARCH 3 2023-07-27 "LIBRECAST" "Librecast Programmer's Manual" .SH NAME q_search \- search for an entry in a smolq queue .SH LIBRARY Librecast library .RI ( liblibrecast ", " \-llibrecast ) .SH SYNOPSIS .nf .B #include .PP .BI "int q_search(q_t " *q ", void *(*" f ")(void *), void *restrict " arg ");" .fi .PP Compile and link with \fI\-llibrecast\fP. .SH DESCRIPTION .BR q_search () searches the queue .IR q to find an entry that matches both .IR f and .IR arg . .PP No locks, so readers may read while we're searching, and writers may write. If something is read while we search, we will still return a positive match for that item, even though it is no longer in the queue. If a writer writes we will not notice that write. If this is a problem, for a particular use-case, an external lock will be required. .PP .SH RETURN VALUE The .BR q_push () function returns 1 if found, zero if not found. On error, -1 is returned and .IR errno is set to indicate the error. .PP .SH ERRORS .PP The function can fail with any of the errors for .BR sem_getvalue (3). .PP .SH SEE ALSO .BR q_job_seek (3), .BR q_pool_create (3), .BR q_pool_destroy (3), .BR q_init (3), .BR q_free (3), .BR q_push (3), .BR q_wait (3), .BR sem_getvalue (3). librecast/doc/q_wait.3000066400000000000000000000022201502456746400151540ustar00rootroot00000000000000.TH Q_WAIT 3 2023-07-25 "LIBRECAST" "Librecast Programmer's Manual" .SH NAME q_wait \- return the next job from the queue, when available .SH LIBRARY Librecast library .RI ( liblibrecast ", " \-llibrecast ) .SH SYNOPSIS .nf .B #include .PP .BI "int q_wait(q_t " *q ", q_job_t " *job ");" .BI "int q_trywait(q_t " *q ", q_job_t " *job ");" .fi .PP Compile and link with \fI\-llibrecast\fP. .SH DESCRIPTION .BR q_wait () atomically fetches the next .IR job in .IR q and sets the .IR job pointer to it. The call blocks until a job is available. .PP .BR q_trywait () is the same as .BR q_wait () except that if the queue read lock cannot be immediately obtained, then the call returns an error .RI ( errno set to .BR EAGAIN ) instead of blocking. .PP .SH RETURN VALUE The .BR q_push () function returns zero on success. On error, -1 is returned and .IR errno is set to indicate the error. .PP .SH ERRORS The function can also fail with the errors for .BR sem_post (3) or .BR sem_wait (3). .PP .SH SEE ALSO .BR q_job_seek (3), .BR q_pool_create (3), .BR q_pool_destroy (3), .BR q_init (3), .BR q_free (3), .BR q_push (3), .BR sem_post (3), .BR sem_wait (3) librecast/examples/000077500000000000000000000000001502456746400146615ustar00rootroot00000000000000librecast/examples/.gitignore000066400000000000000000000000161502456746400166460ustar00rootroot00000000000000recver sender librecast/examples/Makefile.in000066400000000000000000000003451502456746400167300ustar00rootroot00000000000000CFLAGS ?= -g -O2 -Wall -Wextra -pedantic CFLAGS += -I../include -L../src LDLIBS := -llibrecast PROGRAMS := recver sender examples: $(PROGRAMS) .PHONY: clean realclean clean: $(RM) $(PROGRAMS) realclean: clean $(RM) Makefile librecast/examples/recver.c000066400000000000000000000023241502456746400163140ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2025 Brett Sheffield */ /* Librecast receiver example */ #include int main(void) { char data[BUFSIZ] = {0}; ssize_t bytes; int rc = EXIT_FAILURE; /* pessimistic, aren't we? */ /* we start with a Librecast Context (lc_ctx_t) */ lc_ctx_t *lctx = lc_ctx_new(); if (!lctx) return rc; /* create a Librecast Socket (IPv6) */ lc_socket_t *sock = lc_socket_new(lctx); if (!sock) goto free_ctx; /* create a Librecast Channel */ lc_channel_t *chan = lc_channel_new(lctx, "my very first Librecast channel"); /* bind the Channel to the Socket */ lc_channel_bind(sock, chan); /* join the Channel or we won't receive any data */ lc_channel_join(chan); /* (optional) enable RaptorQ encoding (RFC6330) */ lc_channel_coding_set(chan, LC_CODE_FEC_RQ | LC_CODE_FEC_OTI); /* recv some multicast data */ bytes = lc_channel_recv(chan, data, sizeof data, 0); if (bytes == -1) goto free_ctx; printf("received: '%s' (%zi bytes)\n", data, bytes); rc = EXIT_SUCCESS; free_ctx: /* free the Context. This also frees all Sockets, Channels, Routers etc. * created with that Context */ lc_ctx_free(lctx); return rc; } librecast/examples/sender.c000066400000000000000000000026141502456746400163100ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2025 Brett Sheffield */ /* Librecast sender example */ #include int main(void) { char data[] = "I have a dream"; ssize_t bytes; int rc = EXIT_FAILURE; /* pessimistic, aren't we? */ /* we start with a Librecast Context (lc_ctx_t) */ lc_ctx_t *lctx = lc_ctx_new(); if (!lctx) return rc; /* create a Librecast Socket (IPv6) */ lc_socket_t *sock = lc_socket_new(lctx); if (!sock) goto free_ctx; /* create a Librecast Channel */ lc_channel_t *chan = lc_channel_new(lctx, "my very first Librecast channel"); /* bind the Channel to the Socket */ lc_channel_bind(sock, chan); /* enable loopback, so we receive our own packets on the same host */ lc_socket_loop(sock, 1); #if 0 /* enable RaptorQ encoding (RFC6330) */ lc_channel_coding_set(chan, LC_CODE_FEC_RQ | LC_CODE_FEC_OTI); lc_channel_rq_overhead(chan, RQ_OVERHEAD + 5); #endif /* rate-limit sending */ lc_channel_ratelimit(chan, 104857600 /* 100Mbps */ , 0); /* send some multicast data */ bytes = lc_channel_send(chan, data, sizeof data, 0); if (bytes == -1) { perror("lc_channel_send"); goto free_ctx; } printf("sent: '%s' (%zi bytes)\n", data, bytes); rc = EXIT_SUCCESS; /* free the Context. This also frees all Sockets, Channels, Routers etc. * created with that Context */ free_ctx: lc_ctx_free(lctx); return rc; } librecast/include/000077500000000000000000000000001502456746400144665ustar00rootroot00000000000000librecast/include/librecast.h000066400000000000000000000005321502456746400166070ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2017-2021 Brett Sheffield */ /* librecast.h - The librecast API */ #include /* type declarations */ #include /* just the network functions */ #include /* cryptographic functions */ librecast/include/librecast/000077500000000000000000000000001502456746400164365ustar00rootroot00000000000000librecast/include/librecast/blake3.h000066400000000000000000000036221502456746400177530ustar00rootroot00000000000000#ifndef BLAKE3_H #define BLAKE3_H #include #include #ifdef __cplusplus extern "C" { #endif #define BLAKE3_VERSION_STRING "0.3.7" #define BLAKE3_KEY_LEN 32 #define BLAKE3_OUT_LEN 32 #define BLAKE3_BLOCK_LEN 64 #define BLAKE3_CHUNK_LEN 1024 #define BLAKE3_MAX_DEPTH 54 // This struct is a private implementation detail. It has to be here because // it's part of blake3_hasher below. typedef struct { uint32_t cv[8]; uint64_t chunk_counter; uint8_t buf[BLAKE3_BLOCK_LEN]; uint8_t buf_len; uint8_t blocks_compressed; uint8_t flags; } blake3_chunk_state; typedef struct { uint32_t key[8]; blake3_chunk_state chunk; uint8_t cv_stack_len; // The stack size is MAX_DEPTH + 1 because we do lazy merging. For example, // with 7 chunks, we have 3 entries in the stack. Adding an 8th chunk // requires a 4th entry, rather than merging everything down to 1, because we // don't know whether more input is coming. This is different from how the // reference implementation does things. uint8_t cv_stack[(BLAKE3_MAX_DEPTH + 1) * BLAKE3_OUT_LEN]; } blake3_hasher; const char *blake3_version(void); void blake3_hasher_init(blake3_hasher *self); void blake3_hasher_init_keyed(blake3_hasher *self, const uint8_t key[BLAKE3_KEY_LEN]); void blake3_hasher_init_derive_key(blake3_hasher *self, const char *context); void blake3_hasher_init_derive_key_raw(blake3_hasher *self, const void *context, size_t context_len); void blake3_hasher_update(blake3_hasher *self, const void *input, size_t input_len); void blake3_hasher_finalize(const blake3_hasher *self, uint8_t *out, size_t out_len); void blake3_hasher_finalize_seek(const blake3_hasher *self, uint64_t seek, uint8_t *out, size_t out_len); #ifdef __cplusplus } #endif #endif /* BLAKE3_H */ librecast/include/librecast/crypto.h.in000066400000000000000000000036471502456746400205460ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2017-2025 Brett Sheffield */ #ifndef _LIBRECAST_CRYPTO_H #define _LIBRECAST_CRYPTO_H 1 #include @INCBLAKE3@ @INCSODIUM@ #define HASH_BLAKE2 2 #define HASH_BLAKE3 3 @HASH_TYPE@ @HASHSIZE@ @HASH_STATE@ #ifndef crypto_secretbox_keygen #define crypto_secretbox_keygen(a) \ do { \ randombytes_buf(a, crypto_secretbox_KEYBYTES); \ } while(0) #endif #ifndef crypto_sign_PUBLICKEYBYTES # define crypto_sign_PUBLICKEYBYTES 0 #endif #ifndef crypto_box_PUBLICKEYBYTES # define crypto_box_PUBLICKEYBYTES 0 #endif #ifndef crypto_sign_SECRETKEYBYTES # define crypto_sign_SECRETKEYBYTES 0 #endif #ifndef crypto_box_SECRETKEYBYTES # define crypto_box_SECRETKEYBYTES 0 #endif #ifndef crypto_secretbox_NONCEBYTES # define crypto_secretbox_NONCEBYTES 0 # define crypto_secretbox_MACBYTES 0 char * sodium_bin2hex(char *const hex, const size_t hex_maxlen, const unsigned char *const bin, const size_t bin_len); #endif #define CRYPTO_SECRET_OH crypto_secretbox_NONCEBYTES + crypto_secretbox_MACBYTES #define hash_bin2hex sodium_bin2hex #ifdef HASHSIZE #define HEXLEN HASHSIZE * 2 + 1 #endif /* hash arbitrary data */ int hash_generic(unsigned char *hash, size_t hashlen, unsigned char *in, size_t inlen); /* hash arbitrary data with using a key. Key must be 32 bytes for BLAKE3 */ int hash_generic_key(unsigned char *hash, size_t hashlen, unsigned char *in, size_t inlen, unsigned char *key, size_t keylen); /* multi-part hash functions */ #ifdef HASH_TYPE void hash_init(hash_state *state, unsigned char *key, size_t keylen, size_t hashlen); void hash_update(hash_state *state, unsigned char *msg, size_t msglen); void hash_final(hash_state *state, unsigned char *hash, size_t hashlen); #endif /* hexdump hash with length len to file descriptor fd */ void hash_hex_debug(FILE *fd, unsigned char *hash, size_t len); #endif /* _LIBRECAST_CRYPTO_H */ librecast/include/librecast/errors.h000066400000000000000000000123771502456746400201350ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2017-2021 Brett Sheffield */ #ifndef __LIBRECAST_ERRORS_H__ #define __LIBRECAST_ERRORS_H__ 1 #include #ifndef ENODATA # define ENODATA 61 /* No data available */ #endif #define LC_ERROR_CODES(X) \ X(0, LC_ERROR_SUCCESS, "Success") \ X(-1, LC_ERROR_FAILURE, "Failure") \ X(-2, LC_ERROR_PID_OPEN, "Failed to open pidfile") \ X(-3, LC_ERROR_PID_READFAIL, "Failed to read pidfile") \ X(-4, LC_ERROR_PID_INVALID, "Invalid pid") \ X(-5, LC_ERROR_ALREADY_RUNNING, "Daemon already running") \ X(-6, LC_ERROR_PID_WRITEFAIL, "Failed to write to pidfile") \ X(-7, LC_ERROR_DAEMON_FAILURE, "Failed to daemonize") \ X(-8, LC_ERROR_CONFIG_NOTNUMERIC, "Numeric config value not numeric") \ X(-9, LC_ERROR_CONFIG_BOUNDS, "Numeric config value out of bounds") \ X(-10, LC_ERROR_CONFIG_BOOLEAN, "Invalid boolean config value") \ X(-11, LC_ERROR_CONFIG_READFAIL, "Unable to read config file") \ X(-12, LC_ERROR_CONFIG_INVALID, "Error in config file") \ X(-13, LC_ERROR_MALLOC, "Memory allocation error") \ X(-14, LC_ERROR_INVALID_ARGS, "Invalid command line options") \ X(-15, LC_ERROR_DAEMON_STOPPED, "Daemon not running") \ X(-16, LC_ERROR_NET_SEND, "Error sending data") \ X(-17, LC_ERROR_NET_RECV, "Error receiving data") \ X(-18, LC_ERROR_NET_SOCKOPT, "Error setting socket options") \ X(-19, LC_ERROR_CMD_INVALID, "Invalid Command received") \ X(-20, LC_ERROR_SOCKET_CREATE, "Unable to create unix socket") \ X(-21, LC_ERROR_SOCKET_CONNECT, "Unable to connect to unix socket") \ X(-22, LC_ERROR_SOCKET_BIND, "Unable to bind to unix socket") \ X(-23, LC_ERROR_MCAST_JOIN, "Multicast join failed") \ X(-24, LC_ERROR_MCAST_PART, "Multicast part failed") \ X(-25, LC_ERROR_SOCKET_LISTENING, "Socket already listening") \ X(-26, LC_ERROR_BRIDGE_INIT, "Unable to setup bridge control") \ X(-27, LC_ERROR_BRIDGE_EXISTS, "Bridge already exists") \ X(-28, LC_ERROR_BRIDGE_ADD_FAIL, "Bridge creation failed") \ X(-29, LC_ERROR_TAP_ADD_FAIL, "TAP creation failed") \ X(-30, LC_ERROR_BRIDGE_NODEV, "Bridge does not exist") \ X(-31, LC_ERROR_IF_NODEV, "Interface does not exist") \ X(-32, LC_ERROR_IF_BUSY, "Interface already bridged") \ X(-33, LC_ERROR_IF_LOOP, "Interface is a bridge") \ X(-34, LC_ERROR_IF_OPNOTSUPP, "Interface does not support bridging") \ X(-35, LC_ERROR_IF_BRIDGE_FAIL, "Unable to bridge interface") \ X(-36, LC_ERROR_SOCK_IOCTL, "Unable to create ioctl socket") \ X(-37, LC_ERROR_IF_UP_FAIL, "Unable to bring up interface") \ X(-38, LC_ERROR_CTX_REQUIRED, "Librecast context required for this operation") \ X(-39, LC_ERROR_INVALID_BASEADDR, "Invalid hashgroup baseaddr") \ X(-40, LC_ERROR_RANDOM_OPEN, "Unable to open random source") \ X(-41, LC_ERROR_RANDOM_READ, "Unable to read random source") \ X(-42, LC_ERROR_HASH_INIT, "Unable to initialize hash") \ X(-43, LC_ERROR_HASH_UPDATE, "Unable to hash data") \ X(-44, LC_ERROR_HASH_FINAL, "Unable to finalize hash") \ X(-45, LC_ERROR_DB_OPEN, "Unable to open database") \ X(-46, LC_ERROR_DB_EXEC, "Error executing database operation") \ X(-47, LC_ERROR_DB_REQUIRED, "Database required") \ X(-48, LC_ERROR_DB_KEYNOTFOUND, "Requested key not found in database") \ X(-49, LC_ERROR_SOCKET_REQUIRED, "Librecast socket required for this operation") \ X(-50, LC_ERROR_CHANNEL_REQUIRED, "Librecast channel required for this operation") \ X(-51, LC_ERROR_MESSAGE_REQUIRED, "Librecast message required for this operation") \ X(-52, LC_ERROR_MESSAGE_EMPTY, "message has no payload") \ X(-53, LC_ERROR_INVALID_PARAMS, "Invalid arguments to function") \ X(-54, LC_ERROR_MSG_ATTR_UNKNOWN, "Unknown message attribute") \ X(-55, LC_ERROR_THREAD_CANCEL, "Failed to cancel thread") \ X(-56, LC_ERROR_THREAD_JOIN, "Failed to join thread") \ X(-57, LC_ERROR_INVALID_OPCODE, "Invalid opcode") \ X(-58, LC_ERROR_QUERY_REQUIRED, "Librecast query required for this operation") \ X(-59, LC_ERROR_SETSOCKOPT, "Unable to set socket option") #undef X #define LC_ERROR_MSG(code, name, msg) case code: return msg; #define LC_ERROR_ENUM(code, name, msg) name = code, enum { LC_ERROR_CODES(LC_ERROR_ENUM) }; /* log message and return code */ int lc_error_log(int level, int e); /* return human readable error message for e */ char *lc_error_msg(int e); /* print human readable error, using errsv (errno) or progam defined (e) code */ void lc_print_error(int e, int errsv, char *errstr); #endif /* __LIBRECAST_ERRORS_H__ */ librecast/include/librecast/if.h000066400000000000000000000032551502456746400172120ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2017-2023 Brett Sheffield */ #ifndef _LIBRECAST_IF_H #define _LIBRECAST_IF_H 1 #include #include #ifdef __linux__ # include #endif #ifndef IFF_UP # define IFF_UP 0x1 #endif #ifndef IFF_TAP # define IFF_TAP 0x0002 #endif #ifndef IFF_NO_PI # define IFF_NO_PI 0x1000 #endif #define LC_IF_UP IFF_UP #define LC_IF_DOWN 0x0 /* create / destroy bridge */ int lc_bridge_add(lc_ctx_t *ctx, const char *brname); int lc_bridge_del(lc_ctx_t *ctx, const char *brname); /* add / remove interface ifname from bridge brname */ int lc_bridge_addif(lc_ctx_t *ctx, const char *brname, const char *ifname); int lc_bridge_delif(lc_ctx_t *ctx, const char *brname, const char *ifname); /* create new tun/tap interface. Set ifname as interface name, if provided, * otherwise returns the O/S generated name in this buffer. * ifname must be a char array if size IFNAMSIZ. * * Flags: IFF_TUN - TUN device (no Ethernet headers) * IFF_TAP - TAP device * * IFF_NO_PI - Do not provide packet information * IFF_MULTI_QUEUE - Create a queue of multiqueue device */ int lc_tuntap_create(char *ifname, int flags); /* Wrapper for lc_tuntap_create() - create new tap device and copy interface * name to ifname, which must be a buffer of size IFNAMSIZ. */ int lc_tap_create(char *ifname); /* Bring up / tear down interface called ifname * up = LC_IF_UP - bring interface up * up = LC_IF_DOWN - bring interface down */ int lc_link_set(lc_ctx_t *ctx, char *ifname, int up); #endif /* _LIBRECAST_IF_H */ librecast/include/librecast/key.h000066400000000000000000000024641502456746400174050ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2025 Brett Sheffield */ #ifndef _LIBRECAST_KEY_H #define _LIBRECAST_KEY_H 1 #include #include #include #include #include #include /* ensure uint8_t is the same as unsigned char */ static_assert(CHAR_BIT == 8, "CHAR_BIT != 8"); /* generate new public keypair * Flags: * - LC_KEY_SIG => signing keypair * - LC_KEY_ENC => encrypt keypair */ int lc_keypair_new(lc_keypair_t *key, int flags); /* manage keyring */ int lc_keyring_init(lc_keyring_t *keyring, size_t nkeys); void lc_keyring_free(lc_keyring_t *keyring); int lc_keyring_add(lc_keyring_t *keyring, uint8_t *key); int lc_keyring_del(lc_keyring_t *keyring, uint8_t *key); /* return true (-1) if key found in keyring, false (0) if not */ int lc_keyring_has(lc_keyring_t *keyring, uint8_t *key); /* sign token */ int lc_token_new(lc_token_t *token, lc_keypair_t *signing_key, uint8_t *bearer_key, lc_channel_t *chan, uint8_t capbits, uint64_t valid_sec); /* set sending token for channel */ void lc_channel_token_set(lc_channel_t *chan, lc_token_t *token); /* apply filter to channel */ void lc_channel_filter_set(lc_channel_t *chan, lc_filter_t *filter); #endif /* _LIBRECAST_KEY_H */ librecast/include/librecast/mdex.h000066400000000000000000000114031502456746400175430ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2023-2025 Brett Sheffield */ /* mdex.h - Librecast multicast indexing API */ #ifndef _MDEX_H #define _MDEX_H 1 #include #include #define MDEX_STACK_SZ 4096 #define MDEX_DEFAULT_DEPTH -1 /* default depth for recursive indexing -1 = no limit */ /* these two sets of flags must not conflict as they are sometimes combined */ enum { /* flags for mdex entry type (internal use only) */ MDEX_NONE = 0x00000000, MDEX_PTR = 0x00000001, /* entry refers to bytes in memory */ MDEX_FILE = 0x00000002, /* entry refers to bytes in a file */ MDEX_DIR = 0x00000004, /* entry refers to a directory */ MDEX_LINK = 0x00000008, /* entry refers to a symlink */ /* API flags for mdex_add* etc. */ MDEX_ALIAS = 0x00010000, /* pointer to another entry */ MDEX_OTI = 0x00020000, /* entry will be sent with OTI header */ MDEX_RAND = 0x00040000, /* FEC: random ESIs */ MDEX_RECURSE = 0x00080000, /* Recursively index */ MDEX_MOUNT = 0x00100000, /* Do not cross mount points */ MDEX_SYMLINK = 0x00200000, /* Follow symbolic links when recursively indexing */ }; enum { MDEX_DEBUG_FILE = 0x00000001, /* print indexed files to mdex->stream */ }; typedef unsigned char mdex_hash_t[HASHSIZE]; typedef struct mdex_filemeta { mdex_hash_t *dir; /* pointer to directory data */ char *name; /* pointer to NUL-terminated path */ struct stat *sb; /* pointer to stat buffer */ unsigned int ref; /* reference count */ } mdex_filemeta_t; struct mdex_mem_s { size_t size; void * data; }; struct mdex_file_s { size_t size; size_t off; mdex_filemeta_t file; }; typedef struct mdex_stack_s { size_t ptr; size_t len; void ** stack; } mdex_stack_t; struct mdex_s { /* Head of list. Probably also the root of the tree unless we start balancing operations */ mdex_idx_t *head; /* root of tree */ mdex_idx_t *root; /* next available index slot */ mdex_idx_t *next; /* last available index slot */ mdex_idx_t *last; /* head of entry list */ mdex_entry_t *head_entry; /* next available entry slot */ mdex_entry_t *next_entry; /* to track allocations and reusable (deleted) idx + entries */ mdex_stack_t alloc_stack; mdex_stack_t idx_stack; mdex_stack_t entry_stack; /* debug settings */ size_t files; /* number of files/directories in index */ FILE *stream; int debug; /* root directory of mdex (will be trimmed from file aliases in index) */ char *basedir; size_t basedirlen; char *rootdir; size_t rootdirlen; /* how many entries we have allocated space for */ size_t entries; /* page size in bytes */ size_t pagesz; int maxdepth; /* maximum depth for recursive indexing */ int readers; /* reference count (readers) */ int deleted; /* marked for deletion */ }; /* when HASH_SIZE=32, each struct fits into a 64 byte cache line */ struct mdex_idx_s { unsigned char hash[HASHSIZE]; mdex_idx_t *clown; /* With clowns to the left of me */ mdex_idx_t *joker; /* And jokers to the right */ mdex_entry_t *entry; /* Here I am, stuck in the middle with you */ mdex_idx_t *next; }; struct mdex_entry_s { int type; union { struct mdex_mem_s ptr; struct mdex_file_s file; }; mdex_idx_t *idx; mdex_entry_t *next; }; mdex_t *mdex_init(size_t entries); void mdex_free(mdex_t *mdex); int mdex_add(mdex_t *mdex, void *data, size_t len, q_t *q, int flags); int mdex_addfile(mdex_t *mdex, const char *path, q_t *q, int flags); int mdex_get(mdex_t *mdex, unsigned char *hash, size_t hashlen, mdex_entry_t *entry); int mdex_getalias(mdex_t *mdex, const char *path, mdex_entry_t *entry); void mdex_aliashash(const char *path, unsigned char *hash, size_t hashlen); int mdex_put(mdex_t *mdex, unsigned char *hash, size_t hashlen, mdex_entry_t *entry); int mdex_del(mdex_t *mdex, unsigned char *hash, size_t hashlen); int mdex_alias(mdex_t *mdex, unsigned char *alias, size_t aliaslen, unsigned char *hash, size_t hashlen); char *mdex_sharepath(mdex_t *mdex, const char *restrict path); /* create hash of mtree root with key n * used to index mtree in several parts, and to distinguish the root node from * the first data node when nodes = 1 */ int mdex_tree_hash(unsigned char *hash, size_t hashlen, mtree_t *mtree, size_t n); void mdex_tree_hash_sb(unsigned char *hash, size_t hashlen, mtree_t *mtree, size_t n, struct stat *sb, const char *sharepath); void mdex_hash_entry(unsigned char *hash, size_t hashlen, const char *path, struct stat *sb, mdex_hash_t *dir, int entries); /* find root hash for dir in mdex */ int mdex_directory_root(mdex_t *mdex, const char *dir, unsigned char *root); /* calculate root hash for directory */ int mdex_get_directory_root(const char *dir, unsigned char *root); #endif /* _MDEX_H */ librecast/include/librecast/mtree.h000066400000000000000000000031171502456746400177250ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2020-2023 Brett Sheffield */ /* mtree.h - Librecast merkle tree API */ #ifndef _MTREE_H #define _MTREE_H 1 #include #include #include #include #include #include #include "q.h" #define MTREE_CHUNKSIZE 1024 * 32 #define MTREE_BLOCKSIZE 64 #define MTREE_HASHSIZE 32 #define MTREE_THREADMAX 64 static_assert(__builtin_popcount(MTREE_THREADMAX) == 1, "MTREE_THREADMAX must be a power of 2"); #define mtree_parent(node) (((node + 1) >> 1) - 1) typedef struct mtree_s mtree_t; struct mtree_s { size_t len; /* total size of base (file) data */ size_t base; /* size of base of tree (pow of 2) */ size_t chunks; /* number of blocks (<= base)) */ size_t nodes; /* count of total nodes in tree */ void *data; /* ptr to the base data */ uint8_t *tree; /* ptr to tree hashes */ }; int mtree_init(mtree_t *tree, size_t sz); void mtree_free(mtree_t *tree); int mtree_build(mtree_t *tree, void * const data, q_t *q); int mtree_verify(mtree_t *tree); size_t mtree_child(mtree_t *tree, size_t node); unsigned char *mtree_diff_map(mtree_t *t1, mtree_t *t2); unsigned char *mtree_diff_subtree(mtree_t *t1, mtree_t *t2, size_t root, unsigned bits); uint8_t *mtree_nnode(mtree_t *tree, size_t node); size_t mtree_subtree_data_min(size_t base, size_t root); size_t mtree_subtree_data_max(size_t base, size_t root); void mtree_hexdump(mtree_t *tree, FILE *fd); void mtree_printmap(unsigned char *map, size_t len, FILE *fd); #endif /* _MTREE_H */ librecast/include/librecast/net.h000066400000000000000000000276211502456746400174050ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2017-2025 Brett Sheffield */ /* librecast/net.h - librecast network API */ #ifndef _LIBRECAST_NET_H #define _LIBRECAST_NET_H #define _GNU_SOURCE /* recvmmsg */ #include #include #include #ifndef MSG_WAITFORONE # define MSG_WAITFORONE 0x00080000 struct mmsghdr { struct msghdr msg_hdr; /* Message header */ unsigned int msg_len; /* Number of received bytes for header */ }; int recvmmsg(int sockfd, struct mmsghdr *msgvec, unsigned int vlen, int flags, struct timespec *timeout); #endif extern int (*lc_msg_logger)(lc_channel_t *, lc_message_t *, void *logdb); /* create new librecast context and set up environment * call lc_ctx_free() when done */ lc_ctx_t *lc_ctx_new(void); /* destroy librecast context and clean up */ void lc_ctx_free(lc_ctx_t *ctx); /* acquire read-lock on object. Increments reference count */ lc_ctx_t *lc_ctx_acquire(lc_ctx_t *ctx); lc_socket_t *lc_socket_acquire(lc_socket_t *sock); lc_channel_t *lc_channel_acquire(lc_channel_t *chan); /* release read-lock on object. Decrements reference count. * Free()s object if no other readers and marked for deletion */ void lc_ctx_release(lc_ctx_t *ctx); void lc_socket_release(lc_socket_t *sock); void lc_channel_release(lc_channel_t *chan); /* create ctx queue and worker threads */ int lc_ctx_qpool_init(lc_ctx_t *ctx, int nthreads); /* resize ctx thread pool */ int lc_ctx_qpool_resize(lc_ctx_t *ctx, int nthreads); /* stop worker threads and free queue */ int lc_ctx_qpool_free(lc_ctx_t *ctx); /* return pointer to context queue */ q_t *lc_ctx_q(lc_ctx_t *ctx); /* set debug level */ int lc_ctx_debug(lc_ctx_t *ctx, int debug); /* set output stream for debug */ FILE *lc_ctx_stream(lc_ctx_t *ctx, FILE *stream); /* create librecast socket */ lc_socket_t *lc_socket_new(lc_ctx_t *ctx); /* create a pair of connected librecast sockets */ int lc_socketpair(lc_ctx_t *ctx, lc_socket_t *sock[2]); /* bind socket to interface with index idx. 0 = ALL (default) */ int lc_socket_bind(lc_socket_t *sock, unsigned int ifx); /* close socket */ void lc_socket_close(lc_socket_t *sock); /* Create a new channel by hashing s of length len */ lc_channel_t *lc_channel_nnew(lc_ctx_t *ctx, unsigned char *s, size_t len); /* Create a new channel from the hash of s which must be a NUL-terminated string */ lc_channel_t *lc_channel_new(lc_ctx_t *ctx, char *s); /* copy a channel into ctx */ lc_channel_t *lc_channel_copy(lc_ctx_t *ctx, lc_channel_t *chan); /* create side band channel from base channel by replacing lower 64 bits with band */ lc_channel_t * lc_channel_sideband(lc_channel_t *base, uint64_t band); /* create side channel from base by hashing additional key material */ lc_channel_t * lc_channel_sidehash(lc_channel_t *base, unsigned char *key, size_t keylen); /* create random channel */ lc_channel_t *lc_channel_random(lc_ctx_t *ctx); /* bind channel to socket */ int lc_channel_bind(lc_socket_t *sock, lc_channel_t *chan); /* unbind channel from socket */ int lc_channel_unbind(lc_channel_t *chan); /* join librecast channel */ int lc_channel_join(lc_channel_t *chan); /* leave a librecast channel */ int lc_channel_part(lc_channel_t *chan); /* set default interface for sockets and channels created with this context */ void lc_ctx_ifx(lc_ctx_t *ctx, unsigned int ifx); /* set ratelimit on ctx - this will be applied to all subsequently created * channels on that ctx */ void lc_ctx_ratelimit(lc_ctx_t *ctx, size_t bps_out, size_t bps_in); /* set channel rate limits */ void lc_channel_ratelimit(lc_channel_t *chan, size_t bps_out, size_t bps_in); /* set/get default coding for sockets and channels created with this context */ int lc_ctx_coding_set(lc_ctx_t *ctx, int coding); int lc_ctx_coding_get(lc_ctx_t *ctx); /* set symmetric key for context */ int lc_ctx_getkey(lc_ctx_t *ctx, lc_key_t *key, int type); int lc_ctx_setkey(lc_ctx_t *ctx, lc_key_t *key, int type); int lc_ctx_set_sym_key(lc_ctx_t *ctx, unsigned char *key, size_t len); int lc_ctx_set_pub_key(lc_ctx_t *ctx, unsigned char *key, size_t len); /* set/get socket coding */ int lc_socket_coding_set(lc_socket_t *sock, int coding); int lc_socket_coding_get(lc_socket_t *sock); /* set/get channel coding */ int lc_channel_coding_set(lc_channel_t *chan, int coding); int lc_channel_coding_get(lc_channel_t *chan); /* set channel key */ int lc_channel_setkey(lc_channel_t *chan, lc_key_t *key, int type); /* get channel key */ int lc_channel_getkey(lc_channel_t *chan, lc_key_t *key, int type); /* set symmetric channel key */ int lc_channel_set_sym_key(lc_channel_t *chan, unsigned char *key, size_t len); /* set public channel key */ int lc_channel_set_pub_key(lc_channel_t *chan, unsigned char *key, size_t len); /* start a thread to answer NACKs and replay messages as required */ int lc_channel_nack_handler(lc_channel_t *chan, int n_seconds); /* similar to lc_channel_nack_handler but with an explicit NACK thread instead * of the built-in one */ int lc_channel_nack_handler_thr(lc_channel_t *chan, int n_seconds, void *(*nack_thread)(void *)); /* logs an outgoing message explicitely for the NACK thread; if lc_channel_nack_handler() * has not been called this is a NOP; not required if using lc_msg_send() to send messages */ int lc_channel_nack_add_log(lc_channel_t *chan, const void *buf, size_t len, lc_seq_t seq); /* configure the channel to check for gaps in sequence number and send NACKs */ int lc_channel_detect_gaps(lc_channel_t *chan); /* check for sequence number gaps and send NACKs if required; if lc_channel_detect_gaps() * has not been called this is a NOP; not required if using lc_msg_recv() or lc_socket_listen() * to receive messages */ int lc_channel_check_seqno(lc_channel_t *chan, lc_seq_t seq); /* blocking socket recv() */ ssize_t lc_socket_recv(lc_socket_t *sock, void *buf, size_t len, int flags); /* non-blocking socket listener, with callbacks */ int lc_socket_listen(lc_socket_t *sock, void (*callback_msg)(lc_message_t*), void (*callback_err)(int)); /* stop listening on socket */ int lc_socket_listen_cancel(lc_socket_t *sock); /* send to all channels bound to a socket */ ssize_t lc_socket_send(lc_socket_t *sock, const void *buf, size_t len, int flags); ssize_t lc_socket_sendmsg(lc_socket_t *sock, struct msghdr *msg, int flags); /* send to channel. Channel must be bound to Librecast socket with * lc_channel_bind() first. */ ssize_t lc_channel_send(lc_channel_t *chan, const void *buf, size_t len, int flags); ssize_t lc_channel_sendmsg(lc_channel_t *chan, struct msghdr *msg, int flags); /* blocking channel recv() */ ssize_t lc_channel_recv(lc_channel_t *chan, void *buf, size_t len, int flags); ssize_t lc_channel_recvmsg(lc_channel_t *chan, struct msghdr *msg, int flags); /* blocking message receive */ ssize_t lc_msg_recv(lc_socket_t *sock, lc_message_t *msg); ssize_t lc_socket_recvmsg(lc_socket_t *sock, struct msghdr *msg, int flags); int lc_socket_recvmmsg(lc_socket_t *sock, struct mmsghdr *msgvec, unsigned int vlen, int flags, struct timespec *timeout); /* socket recv functions which return destination channel in dst */ ssize_t lc_socket_multi_recv(lc_socket_t *sock, void *buf, size_t len, int flags, lc_channel_t **dst); ssize_t lc_socket_multi_recvmsg(lc_socket_t *sock, struct msghdr *msg, int flags, lc_channel_t **dst); /* send a message to a channel */ ssize_t lc_msg_send(lc_channel_t *chan, lc_message_t *msg); ssize_t lc_msg_sendto(int sock, const void *buf, size_t len, struct sockaddr_in6 *addr, int flags); /* get/set socket options */ int lc_socket_getopt(lc_socket_t *sock, int optname, void *optval, socklen_t *optlen); int lc_socket_setopt(lc_socket_t *sock, int optname, const void *optval, socklen_t optlen); /* turn socket loopback on (val = 1) or off (val = 0)*/ int lc_socket_loop(lc_socket_t *sock, int val); /* set multicast TTL (hop limit) for this socket to val */ int lc_socket_ttl(lc_socket_t *sock, int val); /* return router for socket */ lc_router_t *lc_socket_router(lc_socket_t *sock); /* manage message structures */ /* initialize message structure */ void *lc_msg_init(lc_message_t *msg); /* allocate message struture of size len */ int lc_msg_init_size(lc_message_t *msg, size_t len); /* initialize message from supplied data of size len * if not NULL, function f will be called to free the structure with hint as an argument */ int lc_msg_init_data(lc_message_t *msg, void *data, size_t len, lc_free_fn_t *f, void *hint); /* free message */ void lc_msg_free(void *msg); /* hash message data and source address * call with pre-allocated buffer id of size len */ int lc_msg_id(lc_message_t *msg, unsigned char *id, size_t len); /* return pointer to message data */ void *lc_msg_data(lc_message_t *msg); /* get message attributes */ int lc_msg_get(lc_message_t *msg, lc_msg_attr_t attr, void **value); /* set message attributes */ int lc_msg_set(lc_message_t *msg, lc_msg_attr_t attr, void *value); /* return raw network socket */ int lc_socket_raw(lc_socket_t *sock); int lc_channel_socket_raw(lc_channel_t *chan); /* return context for socket/channel */ lc_ctx_t *lc_socket_ctx(lc_socket_t *sock); lc_ctx_t *lc_channel_ctx(lc_channel_t *chan); /* find socket by file descriptor */ lc_socket_t * lc_socket_by_fd(lc_ctx_t *ctx, int fd); /* return lcrq handle */ rq_t *lc_channel_rq(lc_channel_t *chan); /* set number of packets of RaptorQ overhead (OH) to send automatically for channel * if unset (default: -1), no automatic sending will occur. * When > 0, functions like lc_channel_send() will automatically send K' + OH * packets in a single call. Returns new value. */ int lc_ctx_rq_overhead(lc_ctx_t *ctx, int overhead); int lc_channel_rq_overhead(lc_channel_t *chan, int overhead); int lc_channel_oti_peek(lc_channel_t *chan, rq_oti_t *oti, rq_scheme_t *scheme); /* return socket bound to this channel */ lc_socket_t *lc_channel_socket(lc_channel_t *chan); /* return socket address for this channel */ struct sockaddr_in6 *lc_channel_sockaddr(lc_channel_t *chan); /* return struct in6_addr for this channel */ struct in6_addr *lc_channel_in6addr(lc_channel_t *chan); /* return channel hash */ unsigned char *lc_channel_get_hash(lc_channel_t *chan); /* search context and return channel */ lc_channel_t *lc_socket_channel_by_address(lc_socket_t *sock, struct in6_addr *addr); lc_channel_t *lc_channel_by_address(lc_ctx_t *lctx, struct in6_addr *addr); lc_channel_t *lc_channel_by_hash(lc_ctx_t *lctx, unsigned char *hash, size_t hashlen); /* search context for channel by both hash and bound socket, as there can be more than one channel with the same hash. */ lc_channel_t *lc_channel_socket_by_hash(lc_socket_t *sock, unsigned char *hash, size_t hashlen); /* create IPv6 multicast addr from supplied hash and flags */ void lc_hashtoaddr(struct in6_addr *addr, unsigned char *hash, size_t hashlen, unsigned char flags); /* Create a new channel using supplied hash, flags and port */ lc_channel_t * lc_channel_hash(lc_ctx_t *ctx, unsigned char *hash, size_t hashlen, unsigned char flags, short port); /* create new channel from grp address and service */ lc_channel_t * lc_channel_init(lc_ctx_t *ctx, struct sockaddr_in6 *sa); /* convenience function for calling lc_channel_init() */ lc_channel_t *lc_channel_init_grp(lc_ctx_t *ctx, struct in6_addr *grp, short port); /* free channel */ void lc_channel_free(lc_channel_t *chan); /* get some random bytes */ int lc_getrandom(void *buf, size_t buflen); /* add/del hash to/from socket Outgoing Interface List (OIL) filter * return 0 on success, -1 on error/not found, setting errno: * ENOENT - not found */ int lc_socket_oil_add(lc_socket_t *sock, unsigned char *hash); int lc_socket_oil_del(lc_socket_t *sock, unsigned char *hash); /* return 0 if hash is found in socket Outgoing Interface List (OIL) * returns -1 on error/not found, setting errno: * ENOENT - not found */ int lc_socket_oil_cmp(lc_socket_t *sock, unsigned char *hash); #endif /* _LIBRECAST_NET_H */ librecast/include/librecast/q.h000066400000000000000000000027511502456746400170540ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2023 Brett Sheffield */ /* smolq - a very simple threadpool and job queue * * Uses a fixed size ring buffer style queue of 65536. Uses just over 1MiB. * * A job consists of a start function and argument for a thread. * * The job queue is initialized with q_init() and freed with q_free(). * This can be passed to a threadpool as the argument when calling * q_pool_create(). */ #ifndef _SMOL_Q #define _SMOL_Q 1 #include #include #include #include #include #include #include #include struct q_job_s { void *(*f)(void *); void *arg; }; struct q_s { q_job_t job[UINT16_MAX + 1]; /* 1 MiB => ~256 pages */ uint16_t ridx; /* read index (HEAD) */ uint16_t widx; /* write index (TAIL) */ sem_t rlock; /* read semaphore */ sem_t wlock; /* write semaphore */ }; int q_init(q_t *q); int q_free(q_t *q); void *q_job_seek(void *arg); int q_pool_create(pthread_t tid[], int nthreads, void *(*f)(void *), void *restrict arg); int q_pool_destroy(pthread_t tid[], int nthreads); int q_push(q_t *q, void *(*f)(void *), void *restrict arg); int q_search(q_t *q, void *(*f)(void *), void *restrict arg); int q_trypush(q_t *q, void *(*f)(void *), void *restrict arg); int q_trywait(q_t *q, q_job_t *job); int q_wait(q_t *q, q_job_t *job); #endif /* _SMOL_Q */ librecast/include/librecast/router.h000066400000000000000000000101621502456746400201270ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2024 Brett Sheffield */ /* librecast/router.h - librecast router API */ #ifndef _LIBRECAST_ROUTER_H #define _LIBRECAST_ROUTER_H 1 #include #include #include /* Router API declarations */ #define ROUTER_THREADS 2 /* minimum router threads */ typedef enum { LC_ROUTER_FLAG_FIXED = 0x01, /* ports not resizable */ LC_ROUTER_FLAG_VISIT = 0x02, /* visited, used in searches */ LC_ROUTER_FLAG_RUNNING = 0x04, /* router is running */ } lc_router_flags_t; typedef enum { LC_PORT_UP = 1, /* port enabled */ LC_PORT_STP = 2, /* STP running on this port */ LC_PORT_FWD = 4, /* forwarding enabled */ LC_PORT_FLOOD = 8, /* port flooding - bypass OIL filter checks */ } lc_portstatus_t; typedef enum { LC_TOPO_NONE, /* do not connect anything */ LC_TOPO_CHAIN, /* routers are daisy-chained */ LC_TOPO_RING, /* ring topology */ LC_TOPO_TREE, /* loop-free spanning tree */ LC_TOPO_STAR, /* root router is connected to all others */ LC_TOPO_MESH, /* full mesh (all routers directly connected) */ LC_TOPO_RANDOM, /* surprise me */ LC_TOPO_BUTTERFLY, /* a fixed topology of 6 routers */ LC_TOPO_HONEYCOMB, /* 3 routers inside n rings of hexagons */ } lc_topology_t; lc_router_t *lc_router_new(lc_ctx_t *ctx, unsigned int ports, int flags); /* return number of routers in ctx */ int lc_router_count(lc_ctx_t *ctx); /* create n routers, connecting them with topology t */ int lc_router_net(lc_ctx_t *ctx, lc_router_t *r[], int n, lc_topology_t t, unsigned int ports, int flags); int lc_router_connect(lc_router_t *r1, lc_router_t *r2); void lc_router_free(lc_router_t *router); int lc_router_start(lc_router_t *router); int lc_router_stop(lc_router_t *router); int lc_router_socket_add(lc_router_t *router, lc_socket_t *sock); int lc_router_socket_del(lc_router_t *router, lc_socket_t *sock); int lc_router_socket_get(lc_router_t *router, unsigned int port); int lc_router_socket_set(lc_router_t *router, unsigned int port, int status); /* callbacks */ int lc_router_onready(lc_router_t *r, void *(*cb)(void *), void *arg); /* copy chan and bind to port on router */ int lc_router_channel_bind(lc_router_t *router, unsigned int port, lc_channel_t *chan); int lc_router_channel_unbind(lc_router_t *router, unsigned int port, lc_channel_t *chan); /* set/unset portstatus for router port. If port == -1 => all ports */ int lc_router_port_set(lc_router_t *router, unsigned int port, int status); int lc_router_port_unset(lc_router_t *router, unsigned int port, int status); /* up/down router port. If port == -1 => all ports */ int lc_router_port_down(lc_router_t *router, unsigned int port); int lc_router_port_up(lc_router_t *router, unsigned int port); /* return -1 if r1 has path to r2, 0 if not. r[] is the array of routers, n is * the number of routers */ int lc_router_has_path(lc_router_t *r[], int n, lc_router_t *r1, lc_router_t *r2); /* return -1 if routing loop exists, 0 if not */ int lc_router_net_hasloop(lc_router_t *r[], int n); /* lock/unlock router mutex */ int lc_router_lock(lc_router_t *r); int lc_router_trylock(lc_router_t *r); int lc_router_unlock(lc_router_t *r); /* lock a pair of routers */ int lc_router_lockpair(lc_router_t *r1, lc_router_t *r2); /* acquire read-lock on object. Increments reference count */ lc_router_t *lc_router_acquire(lc_router_t *r); void lc_router_release(lc_router_t *r); #ifdef _LIBRECAST_PRIVATE /* Private declarations - for librecast internal use only */ #define MAX_MTU 1500 struct pkt_s { char data[MAX_MTU]; size_t len; }; struct lc_router_s { lc_router_t *next; lc_ctx_t *ctx; struct pkt_s *buf; unsigned int bufs; unsigned int ridx; unsigned int widx; pthread_t recver; /* router recv thread */ pthread_mutex_t mtx; /* callbacks */ void *(*onready)(void *); void *onready_arg; #if HAVE_EPOLL_CREATE1 int epollfd; #endif int readers; /* reference count (readers) */ int deleted; /* marked for deletion */ int flags; unsigned int ports; lc_socket_t **port; }; #endif /* _LIBRECAST_PRIVATE */ #endif /* _LIBRECAST_ROUTER_H */ librecast/include/librecast/sync.h000066400000000000000000000101311502456746400175570ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2023-2025 Brett Sheffield */ /* sync.h - Librecast data & file syncing API */ #ifndef _LC_SYNC_H #define _LC_SYNC_H 1 #include #include #include #include #define NET_LOOPBACK 1 #define SYNC_SEND_THREADS 1 #define SYNC_MAX_RECVERS 16 /* maximum number of simultaneous receive groups */ enum { /* flags for lc_sync functions */ SYNC_NONE = 0x00000000, SYNC_LOOPBACK = 0x00000001, /* set multicast loopback on */ SYNC_SUBDIR = 0x00000002, /* create subdirectory within target */ SYNC_OWNER = 0x00000004, /* set owner */ SYNC_GROUP = 0x00000008, /* set group */ SYNC_MODE = 0x00000010, /* set mode */ SYNC_MTIME = 0x00000020, /* set mtime */ SYNC_ATIME = 0x00000040, /* set atime */ SYNC_RECURSE = 0x00000080, /* sync recursively */ }; typedef uint8_t hash_t[HASHSIZE]; typedef struct net_tree_s net_tree_t; struct net_tree_s { uint64_t size; /* Total size, in bytes */ uint64_t mtime_s;/* Time of last modification - sec */ uint64_t mtime_n;/* - nsec */ uint64_t atime_s;/* Time of last access - sec */ uint64_t atime_n;/* - nsec */ uint32_t uid; /* User ID of owner */ uint32_t gid; /* Group ID of owner */ uint16_t mode; /* File type and mode */ uint16_t namesz; /* length of filename */ /* name is prefixed to tree */ /* (symlink target replaces tree hashes) */ uint32_t pad; unsigned char tree[]; /* tree or directory hashes */ }; /* structure for passing stats from sync functions */ struct lc_stat_s { size_t byt_gross; /* bytes: gross bytes transferred */ size_t byt_info; /* bytes: information bytes */ size_t chunks_tot; /* total chunks to transfer */ size_t chunks_io; /* chunks transferred */ size_t chunks_fail; /* chunk transfer failures */ size_t pkts_io; /* packets in/out */ size_t sym_origin; /* original source symbols */ size_t sym_repair; /* repair symbols */ }; /* share files in mdex on interface ifx (0 = all interfaces) */ #ifdef HAVE_LIBLCRQ lc_share_t * lc_share(lc_ctx_t *lctx, mdex_t *mdex, unsigned int ifx, lc_stat_t *stats, lc_sync_options_t *opt, int flags); void lc_unshare(lc_share_t *share); lc_share_t *lc_share_acquire(lc_share_t *share); void lc_share_release(lc_share_t *share); ssize_t lc_recvdir(lc_ctx_t *lctx, unsigned char *hash, net_tree_t **dir, lc_stat_t *stats, lc_sync_options_t *opt, int flags); ssize_t lc_recvtree(lc_ctx_t *lctx, unsigned char *hash, mtree_t *tree, lc_stat_t *stats, lc_sync_options_t *opt, int flags); ssize_t lc_recvchunk(lc_ctx_t *lctx, unsigned char *hash, void *data, const size_t len, lc_stat_t *stats, lc_sync_options_t *opt, int flags); ssize_t lc_senddir(lc_ctx_t *lctx, unsigned char *hash, net_tree_t *dir, lc_stat_t *stats, lc_sync_options_t *opt, int flags); ssize_t lc_sendtree(lc_ctx_t *lctx, unsigned char *hash, const mtree_t *tree, lc_stat_t *stats, lc_sync_options_t *opt, int flags); ssize_t lc_sendchunk(lc_ctx_t *lctx, unsigned char *hash, const void *data, const size_t len, lc_stat_t *stats, lc_sync_options_t *opt, int flags); #endif /* local blob/file sync */ int lc_memsync(void *dst, void *src, const size_t n, q_t *q, lc_stat_t *stats, lc_sync_options_t *opt, int flags); int lc_syncfilelocal(const char *dst, char *src, q_t *q, lc_stat_t *stats, lc_sync_options_t *opt, int flags); /* network sync */ #ifdef HAVE_LIBLCRQ ssize_t lc_sync(lc_ctx_t *lctx, unsigned char *hash, void *data, const size_t len, q_t *q, lc_stat_t *stats, lc_sync_options_t *opt, int flags); ssize_t lc_syncfile(lc_ctx_t *lctx, unsigned char *hash, const char *pathname, q_t *q, lc_stat_t *stats, lc_sync_options_t *opt, int flags); ssize_t lc_syncfile_hash(lc_ctx_t *lctx, char *src, const char *dst, q_t *q, lc_stat_t *stats, lc_sync_options_t *opt, int flags); #endif /* map local file into memory */ void *lc_mmapfile(const char *pathname, size_t *len, int prot, int flags, off_t offset, struct stat *sb); #endif /* _LC_SYNC_H */ librecast/include/librecast/types.h.in000066400000000000000000000153371502456746400203710ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2017-2025 Brett Sheffield */ #ifndef _LIBRECAST_TYPES_H #define _LIBRECAST_TYPES_H 1 #define _GNU_SOURCE /* recvmmsg */ #include #include #include #include #include #include #include #include @INCLUDE_LCRQ@ #ifndef ECHRNG # ifdef ELAST # define ECHRNG ELAST + 1 # else # define ECHRNG 44 /* Channel number out of range */ # endif #endif #ifndef ENOLINK # define ENOLINK 95 /* Link has been severed */ #endif #ifndef ENOKEY # define ENOKEY 126 /* Required key not available */ #endif #ifndef EKEYEXPIRED # define EKEYEXPIRED 127 /* Key has expired */ #endif #ifndef EKEYREJECTED # define EKEYREJECTED 129 /* Key was rejected by service */ #endif #ifndef UIO_MAXIOV # define UIO_MAXIOV 1024 #endif #define LC_DEFAULT_PORT 4242 #define LC_DEFAULT_FLAGS 0x1e #define LC_BRIDGE_NAME "lc0" #define LC_DATABASE_COUNT 32 #define DEFAULT_MULTICAST_LOOP 0 #define DEFAULT_MULTICAST_HOPS 255 #define LC_DEFAULT_RQ_T 1024 /* default symbol size for RaptorQ */ /* bloom filter params */ #define BLOOM_LEN 16777216 /* 16MiB */ #define BLOOM_HASHES 8 /* define flag to drop packets when used some send/recv calls * 0x400 is unused on *BSD and is used for MSG_SYN on Linux * so we can safely borrow this */ #define MSG_DROP 0x400 typedef uint64_t lc_seq_t; typedef uint64_t lc_rnd_t; typedef uint64_t lc_len_t; typedef struct lc_ctx_t lc_ctx_t; typedef struct lc_socket_t lc_socket_t; typedef struct lc_channel_t lc_channel_t; typedef struct lc_msg_head_t lc_msg_head_t; typedef struct lc_query_t lc_query_t; typedef struct lc_query_param_t lc_query_param_t; typedef struct lc_router_s lc_router_t; typedef struct lc_stat_s lc_stat_t; typedef struct lc_sync_options_s lc_sync_options_t; typedef struct mdex_s mdex_t; typedef struct mdex_idx_s mdex_idx_t; typedef struct mdex_entry_s mdex_entry_t; typedef struct mdex_dir_s mdex_dir_t; typedef struct mtree_s mtree_t; typedef struct lc_share_s lc_share_t; typedef void *lc_free_fn_t(void *msg, void *hint); typedef struct net_tree_s net_tree_t; typedef struct q_job_s q_job_t; typedef struct q_s q_t; #ifndef rq_t typedef struct rq_s rq_t; #endif #ifndef rq_oti_t typedef uint64_t rq_oti_t; #endif #ifndef rq_scheme_t typedef uint32_t rq_scheme_t; #endif #define LC_OPCODES(X) \ X(0x0, LC_OP_DATA, "DATA", lc_op_data) \ X(0x1, LC_OP_PING, "PING", lc_op_ping) \ X(0x2, LC_OP_PONG, "PONG", lc_op_pong) \ X(0x3, LC_OP_GET, "GET", lc_op_get) \ X(0x4, LC_OP_SET, "SET", lc_op_set) \ X(0x5, LC_OP_DEL, "DEL", lc_op_del) \ X(0x6, LC_OP_RET, "RET", lc_op_ret) \ X(0x7, LC_OP_MAX, "MAX", lc_op_data) #undef X #define LC_OPCODE_ENUM(code, name, text, f) name = code, #define LC_OPCODE_TEXT(code, name, text, f) case code: return text; #define LC_OPCODE_FUN(code, name, text, f) case code: if (f) f(sc, msg); break; typedef enum { LC_OPCODES(LC_OPCODE_ENUM) } lc_opcode_t; typedef enum { LC_DB_MODE_DUP = 1, LC_DB_MODE_LEFT = 2, LC_DB_MODE_RIGHT = 4, LC_DB_MODE_BOTH = 6, LC_DB_MODE_INT = 8, } lc_db_mode_t; typedef enum { LC_QUERY_NOOP = 0, LC_QUERY_EQ = 1, LC_QUERY_NE = 2, LC_QUERY_LT = 4, LC_QUERY_GT = 8, LC_QUERY_TIME = 16, LC_QUERY_SRC = 32, LC_QUERY_DST = 64, LC_QUERY_CHANNEL = 128, LC_QUERY_DB = 256, LC_QUERY_KEY = 512, LC_QUERY_MIN = 1024, LC_QUERY_MAX = 2048, } lc_query_op_t; typedef enum { LC_ATTR_DATA, LC_ATTR_LEN, LC_ATTR_OPCODE, } lc_msg_attr_t; typedef enum { LC_TLV_NOP = 0x00, LC_TLV_DST = 0x01, LC_TLV_SRC = 0x02, LC_TLV_HASH = 0x04, LC_TLV_JOIN = 0x08, LC_TLV_PART = 0x10, LC_TLV_STOP = 0x20, LC_TLV_PEER = 0x40, } lc_tlv_type_t; /* channel encoding constants */ typedef enum { LC_CODE_NONE = 0x00, LC_CODE_SYMM = 0x01, /* symmetric encryption */ LC_CODE_PUBK = 0x02, /* public key encryption */ LC_CODE_SIGN = 0x04, /* public key signing */ LC_CODE_FEC_RQ = 0x08, /* FEC: RaptorQ (RFC 6330) */ LC_CODE_FEC_RAND = 0x10, /* FEC: random ESIs */ LC_CODE_FEC_OTI = 0x20 /* FEC: send/recv OTI headers */ } lc_coding_t; typedef enum { LC_SHARE_LOOPBACK = 1, } lc_share_flags_t; enum { LCTX_DEBUG_SYNCFILE = 0x0001, /* print files synced to lctx->stream */ }; typedef enum { LC_SOCK_IN6 = 0, /* IPv6 multicast */ LC_SOCK_PAIR = 1, /* connected socket pair */ LC_SOCK_WSS = 2, /* Websocket (RFC 6455) */ LC_SOCK_RTC = 3, /* WebRTC */ } lc_socktype_t; enum { LC_CHAN_EXEC = 0x1, LC_CHAN_WRITE = 0x2, LC_CHAN_READ = 0x4, }; enum { LC_KEY_SYM = 0x1, LC_KEY_SIG = 0x2, LC_KEY_ENC = 0x3, }; typedef struct { unsigned char pk[MAX(crypto_sign_PUBLICKEYBYTES, crypto_box_PUBLICKEYBYTES)]; unsigned char sk[MAX(crypto_sign_SECRETKEYBYTES, crypto_box_SECRETKEYBYTES)]; int type; } lc_keypair_t; typedef struct lc_key_s { unsigned char *key; size_t keylen; } lc_key_t; typedef struct lc_keyring_s { uint8_t **key; size_t nkeys; size_t len; } lc_keyring_t; typedef struct lc_filter_s { lc_keyring_t *keyring; uint8_t capbits; } lc_filter_t; typedef struct lc_token_s { uint8_t version; uint8_t channel[14]; uint8_t capbits; uint8_t signkey[8]; uint64_t expires; uint8_t bearkey[32]; uint8_t sig[64]; } lc_token_t; typedef struct lc_tlv_s { uint8_t type; uint32_t len; uint8_t value[]; } __attribute__((__packed__)) lc_tlv_t; typedef struct lc_tlv_hash_s { uint8_t type; uint32_t len; uint8_t value[HASHSIZE]; } __attribute__((__packed__)) lc_tlv_hash_t; typedef struct lc_message_t { uint64_t timestamp; struct in6_addr dst; struct in6_addr src; lc_seq_t seq; lc_rnd_t rnd; lc_len_t len; /* byte length of message data */ size_t bytes; /* outer byte size of packet */ uint32_t sockid; lc_opcode_t op; lc_free_fn_t *free; lc_channel_t *chan; char srcaddr[INET6_ADDRSTRLEN]; char dstaddr[INET6_ADDRSTRLEN]; void *hint; void *data; } lc_message_t; typedef struct lc_messagelist_t { char *hash; uint64_t timestamp; void *data; struct lc_messagelist_t *next; } lc_messagelist_t; typedef struct { lc_len_t size; void *data; } lc_val_t; /* structure to pass to socket listening thread */ typedef struct lc_socket_call_s { lc_socket_t *sock; void (*callback_msg)(lc_message_t*); void (*callback_err)(int); } lc_socket_call_t; extern void (*lc_op_handler[LC_OP_MAX])(lc_socket_call_t *, lc_message_t *); #endif /* _LIBRECAST_TYPES_H */ librecast/install-sh000066400000000000000000001051161502456746400150500ustar00rootroot00000000000000#! /bin/sh # Configuration validation subroutine script. # Copyright 1992-2022 Free Software Foundation, Inc. # shellcheck disable=SC2006,SC2268 # see below for rationale timestamp='2022-01-03' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 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 . # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that # program. This Exception is an additional permission under section 7 # of the GNU General Public License, version 3 ("GPLv3"). # Please send patches to . # # Configuration subroutine to validate and canonicalize a configuration type. # Supply the specified configuration type as an argument. # If it is invalid, we print an error message on stderr and exit with code 1. # Otherwise, we print the canonical config type on stdout and succeed. # You can get the latest version of this script from: # https://git.savannah.gnu.org/cgit/config.git/plain/config.sub # This file is supposed to be the same for all GNU packages # and recognize all the CPU types, system types and aliases # that are meaningful with *any* GNU software. # Each package is responsible for reporting which valid configurations # it does not support. The user should be able to distinguish # a failure to support a valid configuration from a meaningless # configuration. # The goal of this file is to map all the various variations of a given # machine specification into a single specification in the form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM # or in some cases, the newer four-part form: # CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM # It is wrong to echo any other type of specification. # The "shellcheck disable" line above the timestamp inhibits complaints # about features and limitations of the classic Bourne shell that were # superseded or lifted in POSIX. However, this script identifies a wide # variety of pre-POSIX systems that do not have POSIX shells at all, and # even some reasonably current systems (Solaris 10 as case-in-point) still # have a pre-POSIX /bin/sh. me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] CPU-MFR-OPSYS or ALIAS Canonicalize a configuration name. Options: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.sub ($timestamp) Copyright 1992-2022 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit ;; --version | -v ) echo "$version" ; exit ;; --help | --h* | -h ) echo "$usage"; exit ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" >&2 exit 1 ;; *local*) # First pass through any local machine types. echo "$1" exit ;; * ) break ;; esac done case $# in 0) echo "$me: missing argument$help" >&2 exit 1;; 1) ;; *) echo "$me: too many arguments$help" >&2 exit 1;; esac # Split fields of configuration type # shellcheck disable=SC2162 saved_IFS=$IFS IFS="-" read field1 field2 field3 field4 <&2 exit 1 ;; *-*-*-*) basic_machine=$field1-$field2 basic_os=$field3-$field4 ;; *-*-*) # Ambiguous whether COMPANY is present, or skipped and KERNEL-OS is two # parts maybe_os=$field2-$field3 case $maybe_os in nto-qnx* | linux-* | uclinux-uclibc* \ | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* \ | netbsd*-eabi* | kopensolaris*-gnu* | cloudabi*-eabi* \ | storm-chaos* | os2-emx* | rtmk-nova*) basic_machine=$field1 basic_os=$maybe_os ;; android-linux) basic_machine=$field1-unknown basic_os=linux-android ;; *) basic_machine=$field1-$field2 basic_os=$field3 ;; esac ;; *-*) # A lone config we happen to match not fitting any pattern case $field1-$field2 in decstation-3100) basic_machine=mips-dec basic_os= ;; *-*) # Second component is usually, but not always the OS case $field2 in # Prevent following clause from handling this valid os sun*os*) basic_machine=$field1 basic_os=$field2 ;; zephyr*) basic_machine=$field1-unknown basic_os=$field2 ;; # Manufacturers dec* | mips* | sequent* | encore* | pc533* | sgi* | sony* \ | att* | 7300* | 3300* | delta* | motorola* | sun[234]* \ | unicom* | ibm* | next | hp | isi* | apollo | altos* \ | convergent* | ncr* | news | 32* | 3600* | 3100* \ | hitachi* | c[123]* | convex* | sun | crds | omron* | dg \ | ultra | tti* | harris | dolphin | highlevel | gould \ | cbm | ns | masscomp | apple | axis | knuth | cray \ | microblaze* | sim | cisco \ | oki | wec | wrs | winbond) basic_machine=$field1-$field2 basic_os= ;; *) basic_machine=$field1 basic_os=$field2 ;; esac ;; esac ;; *) # Convert single-component short-hands not valid as part of # multi-component configurations. case $field1 in 386bsd) basic_machine=i386-pc basic_os=bsd ;; a29khif) basic_machine=a29k-amd basic_os=udi ;; adobe68k) basic_machine=m68010-adobe basic_os=scout ;; alliant) basic_machine=fx80-alliant basic_os= ;; altos | altos3068) basic_machine=m68k-altos basic_os= ;; am29k) basic_machine=a29k-none basic_os=bsd ;; amdahl) basic_machine=580-amdahl basic_os=sysv ;; amiga) basic_machine=m68k-unknown basic_os= ;; amigaos | amigados) basic_machine=m68k-unknown basic_os=amigaos ;; amigaunix | amix) basic_machine=m68k-unknown basic_os=sysv4 ;; apollo68) basic_machine=m68k-apollo basic_os=sysv ;; apollo68bsd) basic_machine=m68k-apollo basic_os=bsd ;; aros) basic_machine=i386-pc basic_os=aros ;; aux) basic_machine=m68k-apple basic_os=aux ;; balance) basic_machine=ns32k-sequent basic_os=dynix ;; blackfin) basic_machine=bfin-unknown basic_os=linux ;; cegcc) basic_machine=arm-unknown basic_os=cegcc ;; convex-c1) basic_machine=c1-convex basic_os=bsd ;; convex-c2) basic_machine=c2-convex basic_os=bsd ;; convex-c32) basic_machine=c32-convex basic_os=bsd ;; convex-c34) basic_machine=c34-convex basic_os=bsd ;; convex-c38) basic_machine=c38-convex basic_os=bsd ;; cray) basic_machine=j90-cray basic_os=unicos ;; crds | unos) basic_machine=m68k-crds basic_os= ;; da30) basic_machine=m68k-da30 basic_os= ;; decstation | pmax | pmin | dec3100 | decstatn) basic_machine=mips-dec basic_os= ;; delta88) basic_machine=m88k-motorola basic_os=sysv3 ;; dicos) basic_machine=i686-pc basic_os=dicos ;; djgpp) basic_machine=i586-pc basic_os=msdosdjgpp ;; ebmon29k) basic_machine=a29k-amd basic_os=ebmon ;; es1800 | OSE68k | ose68k | ose | OSE) basic_machine=m68k-ericsson basic_os=ose ;; gmicro) basic_machine=tron-gmicro basic_os=sysv ;; go32) basic_machine=i386-pc basic_os=go32 ;; h8300hms) basic_machine=h8300-hitachi basic_os=hms ;; h8300xray) basic_machine=h8300-hitachi basic_os=xray ;; h8500hms) basic_machine=h8500-hitachi basic_os=hms ;; harris) basic_machine=m88k-harris basic_os=sysv3 ;; hp300 | hp300hpux) basic_machine=m68k-hp basic_os=hpux ;; hp300bsd) basic_machine=m68k-hp basic_os=bsd ;; hppaosf) basic_machine=hppa1.1-hp basic_os=osf ;; hppro) basic_machine=hppa1.1-hp basic_os=proelf ;; i386mach) basic_machine=i386-mach basic_os=mach ;; isi68 | isi) basic_machine=m68k-isi basic_os=sysv ;; m68knommu) basic_machine=m68k-unknown basic_os=linux ;; magnum | m3230) basic_machine=mips-mips basic_os=sysv ;; merlin) basic_machine=ns32k-utek basic_os=sysv ;; mingw64) basic_machine=x86_64-pc basic_os=mingw64 ;; mingw32) basic_machine=i686-pc basic_os=mingw32 ;; mingw32ce) basic_machine=arm-unknown basic_os=mingw32ce ;; monitor) basic_machine=m68k-rom68k basic_os=coff ;; morphos) basic_machine=powerpc-unknown basic_os=morphos ;; moxiebox) basic_machine=moxie-unknown basic_os=moxiebox ;; msdos) basic_machine=i386-pc basic_os=msdos ;; msys) basic_machine=i686-pc basic_os=msys ;; mvs) basic_machine=i370-ibm basic_os=mvs ;; nacl) basic_machine=le32-unknown basic_os=nacl ;; ncr3000) basic_machine=i486-ncr basic_os=sysv4 ;; netbsd386) basic_machine=i386-pc basic_os=netbsd ;; netwinder) basic_machine=armv4l-rebel basic_os=linux ;; news | news700 | news800 | news900) basic_machine=m68k-sony basic_os=newsos ;; news1000) basic_machine=m68030-sony basic_os=newsos ;; necv70) basic_machine=v70-nec basic_os=sysv ;; nh3000) basic_machine=m68k-harris basic_os=cxux ;; nh[45]000) basic_machine=m88k-harris basic_os=cxux ;; nindy960) basic_machine=i960-intel basic_os=nindy ;; mon960) basic_machine=i960-intel basic_os=mon960 ;; nonstopux) basic_machine=mips-compaq basic_os=nonstopux ;; os400) basic_machine=powerpc-ibm basic_os=os400 ;; OSE68000 | ose68000) basic_machine=m68000-ericsson basic_os=ose ;; os68k) basic_machine=m68k-none basic_os=os68k ;; paragon) basic_machine=i860-intel basic_os=osf ;; parisc) basic_machine=hppa-unknown basic_os=linux ;; psp) basic_machine=mipsallegrexel-sony basic_os=psp ;; pw32) basic_machine=i586-unknown basic_os=pw32 ;; rdos | rdos64) basic_machine=x86_64-pc basic_os=rdos ;; rdos32) basic_machine=i386-pc basic_os=rdos ;; rom68k) basic_machine=m68k-rom68k basic_os=coff ;; sa29200) basic_machine=a29k-amd basic_os=udi ;; sei) basic_machine=mips-sei basic_os=seiux ;; sequent) basic_machine=i386-sequent basic_os= ;; sps7) basic_machine=m68k-bull basic_os=sysv2 ;; st2000) basic_machine=m68k-tandem basic_os= ;; stratus) basic_machine=i860-stratus basic_os=sysv4 ;; sun2) basic_machine=m68000-sun basic_os= ;; sun2os3) basic_machine=m68000-sun basic_os=sunos3 ;; sun2os4) basic_machine=m68000-sun basic_os=sunos4 ;; sun3) basic_machine=m68k-sun basic_os= ;; sun3os3) basic_machine=m68k-sun basic_os=sunos3 ;; sun3os4) basic_machine=m68k-sun basic_os=sunos4 ;; sun4) basic_machine=sparc-sun basic_os= ;; sun4os3) basic_machine=sparc-sun basic_os=sunos3 ;; sun4os4) basic_machine=sparc-sun basic_os=sunos4 ;; sun4sol2) basic_machine=sparc-sun basic_os=solaris2 ;; sun386 | sun386i | roadrunner) basic_machine=i386-sun basic_os= ;; sv1) basic_machine=sv1-cray basic_os=unicos ;; symmetry) basic_machine=i386-sequent basic_os=dynix ;; t3e) basic_machine=alphaev5-cray basic_os=unicos ;; t90) basic_machine=t90-cray basic_os=unicos ;; toad1) basic_machine=pdp10-xkl basic_os=tops20 ;; tpf) basic_machine=s390x-ibm basic_os=tpf ;; udi29k) basic_machine=a29k-amd basic_os=udi ;; ultra3) basic_machine=a29k-nyu basic_os=sym1 ;; v810 | necv810) basic_machine=v810-nec basic_os=none ;; vaxv) basic_machine=vax-dec basic_os=sysv ;; vms) basic_machine=vax-dec basic_os=vms ;; vsta) basic_machine=i386-pc basic_os=vsta ;; vxworks960) basic_machine=i960-wrs basic_os=vxworks ;; vxworks68) basic_machine=m68k-wrs basic_os=vxworks ;; vxworks29k) basic_machine=a29k-wrs basic_os=vxworks ;; xbox) basic_machine=i686-pc basic_os=mingw32 ;; ymp) basic_machine=ymp-cray basic_os=unicos ;; *) basic_machine=$1 basic_os= ;; esac ;; esac # Decode 1-component or ad-hoc basic machines case $basic_machine in # Here we handle the default manufacturer of certain CPU types. It is in # some cases the only manufacturer, in others, it is the most popular. w89k) cpu=hppa1.1 vendor=winbond ;; op50n) cpu=hppa1.1 vendor=oki ;; op60c) cpu=hppa1.1 vendor=oki ;; ibm*) cpu=i370 vendor=ibm ;; orion105) cpu=clipper vendor=highlevel ;; mac | mpw | mac-mpw) cpu=m68k vendor=apple ;; pmac | pmac-mpw) cpu=powerpc vendor=apple ;; # Recognize the various machine names and aliases which stand # for a CPU type and a company and sometimes even an OS. 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) cpu=m68000 vendor=att ;; 3b*) cpu=we32k vendor=att ;; bluegene*) cpu=powerpc vendor=ibm basic_os=cnk ;; decsystem10* | dec10*) cpu=pdp10 vendor=dec basic_os=tops10 ;; decsystem20* | dec20*) cpu=pdp10 vendor=dec basic_os=tops20 ;; delta | 3300 | motorola-3300 | motorola-delta \ | 3300-motorola | delta-motorola) cpu=m68k vendor=motorola ;; dpx2*) cpu=m68k vendor=bull basic_os=sysv3 ;; encore | umax | mmax) cpu=ns32k vendor=encore ;; elxsi) cpu=elxsi vendor=elxsi basic_os=${basic_os:-bsd} ;; fx2800) cpu=i860 vendor=alliant ;; genix) cpu=ns32k vendor=ns ;; h3050r* | hiux*) cpu=hppa1.1 vendor=hitachi basic_os=hiuxwe2 ;; hp3k9[0-9][0-9] | hp9[0-9][0-9]) cpu=hppa1.0 vendor=hp ;; hp9k2[0-9][0-9] | hp9k31[0-9]) cpu=m68000 vendor=hp ;; hp9k3[2-9][0-9]) cpu=m68k vendor=hp ;; hp9k6[0-9][0-9] | hp6[0-9][0-9]) cpu=hppa1.0 vendor=hp ;; hp9k7[0-79][0-9] | hp7[0-79][0-9]) cpu=hppa1.1 vendor=hp ;; hp9k78[0-9] | hp78[0-9]) # FIXME: really hppa2.0-hp cpu=hppa1.1 vendor=hp ;; hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) # FIXME: really hppa2.0-hp cpu=hppa1.1 vendor=hp ;; hp9k8[0-9][13679] | hp8[0-9][13679]) cpu=hppa1.1 vendor=hp ;; hp9k8[0-9][0-9] | hp8[0-9][0-9]) cpu=hppa1.0 vendor=hp ;; i*86v32) cpu=`echo "$1" | sed -e 's/86.*/86/'` vendor=pc basic_os=sysv32 ;; i*86v4*) cpu=`echo "$1" | sed -e 's/86.*/86/'` vendor=pc basic_os=sysv4 ;; i*86v) cpu=`echo "$1" | sed -e 's/86.*/86/'` vendor=pc basic_os=sysv ;; i*86sol2) cpu=`echo "$1" | sed -e 's/86.*/86/'` vendor=pc basic_os=solaris2 ;; j90 | j90-cray) cpu=j90 vendor=cray basic_os=${basic_os:-unicos} ;; iris | iris4d) cpu=mips vendor=sgi case $basic_os in irix*) ;; *) basic_os=irix4 ;; esac ;; miniframe) cpu=m68000 vendor=convergent ;; *mint | mint[0-9]* | *MiNT | *MiNT[0-9]*) cpu=m68k vendor=atari basic_os=mint ;; news-3600 | risc-news) cpu=mips vendor=sony basic_os=newsos ;; next | m*-next) cpu=m68k vendor=next case $basic_os in openstep*) ;; nextstep*) ;; ns2*) basic_os=nextstep2 ;; *) basic_os=nextstep3 ;; esac ;; np1) cpu=np1 vendor=gould ;; op50n-* | op60c-*) cpu=hppa1.1 vendor=oki basic_os=proelf ;; pa-hitachi) cpu=hppa1.1 vendor=hitachi basic_os=hiuxwe2 ;; pbd) cpu=sparc vendor=tti ;; pbb) cpu=m68k vendor=tti ;; pc532) cpu=ns32k vendor=pc532 ;; pn) cpu=pn vendor=gould ;; power) cpu=power vendor=ibm ;; ps2) cpu=i386 vendor=ibm ;; rm[46]00) cpu=mips vendor=siemens ;; rtpc | rtpc-*) cpu=romp vendor=ibm ;; sde) cpu=mipsisa32 vendor=sde basic_os=${basic_os:-elf} ;; simso-wrs) cpu=sparclite vendor=wrs basic_os=vxworks ;; tower | tower-32) cpu=m68k vendor=ncr ;; vpp*|vx|vx-*) cpu=f301 vendor=fujitsu ;; w65) cpu=w65 vendor=wdc ;; w89k-*) cpu=hppa1.1 vendor=winbond basic_os=proelf ;; none) cpu=none vendor=none ;; leon|leon[3-9]) cpu=sparc vendor=$basic_machine ;; leon-*|leon[3-9]-*) cpu=sparc vendor=`echo "$basic_machine" | sed 's/-.*//'` ;; *-*) # shellcheck disable=SC2162 saved_IFS=$IFS IFS="-" read cpu vendor <&2 exit 1 ;; esac ;; esac # Here we canonicalize certain aliases for manufacturers. case $vendor in digital*) vendor=dec ;; commodore*) vendor=cbm ;; *) ;; esac # Decode manufacturer-specific aliases for certain operating systems. if test x$basic_os != x then # First recognize some ad-hoc cases, or perhaps split kernel-os, or else just # set os. case $basic_os in gnu/linux*) kernel=linux os=`echo "$basic_os" | sed -e 's|gnu/linux|gnu|'` ;; os2-emx) kernel=os2 os=`echo "$basic_os" | sed -e 's|os2-emx|emx|'` ;; nto-qnx*) kernel=nto os=`echo "$basic_os" | sed -e 's|nto-qnx|qnx|'` ;; *-*) # shellcheck disable=SC2162 saved_IFS=$IFS IFS="-" read kernel os <&2 exit 1 ;; esac # As a final step for OS-related things, validate the OS-kernel combination # (given a valid OS), if there is a kernel. case $kernel-$os in linux-gnu* | linux-dietlibc* | linux-android* | linux-newlib* \ | linux-musl* | linux-relibc* | linux-uclibc* ) ;; uclinux-uclibc* ) ;; -dietlibc* | -newlib* | -musl* | -relibc* | -uclibc* ) # These are just libc implementations, not actual OSes, and thus # require a kernel. echo "Invalid configuration \`$1': libc \`$os' needs explicit kernel." 1>&2 exit 1 ;; kfreebsd*-gnu* | kopensolaris*-gnu*) ;; vxworks-simlinux | vxworks-simwindows | vxworks-spe) ;; nto-qnx*) ;; os2-emx) ;; *-eabi* | *-gnueabi*) ;; -*) # Blank kernel with real OS is always fine. ;; *-*) echo "Invalid configuration \`$1': Kernel \`$kernel' not known to work with OS \`$os'." 1>&2 exit 1 ;; esac # Here we handle the case where we know the os, and the CPU type, but not the # manufacturer. We pick the logical manufacturer. case $vendor in unknown) case $cpu-$os in *-riscix*) vendor=acorn ;; *-sunos*) vendor=sun ;; *-cnk* | *-aix*) vendor=ibm ;; *-beos*) vendor=be ;; *-hpux*) vendor=hp ;; *-mpeix*) vendor=hp ;; *-hiux*) vendor=hitachi ;; *-unos*) vendor=crds ;; *-dgux*) vendor=dg ;; *-luna*) vendor=omron ;; *-genix*) vendor=ns ;; *-clix*) vendor=intergraph ;; *-mvs* | *-opened*) vendor=ibm ;; *-os400*) vendor=ibm ;; s390-* | s390x-*) vendor=ibm ;; *-ptx*) vendor=sequent ;; *-tpf*) vendor=ibm ;; *-vxsim* | *-vxworks* | *-windiss*) vendor=wrs ;; *-aux*) vendor=apple ;; *-hms*) vendor=hitachi ;; *-mpw* | *-macos*) vendor=apple ;; *-*mint | *-mint[0-9]* | *-*MiNT | *-MiNT[0-9]*) vendor=atari ;; *-vos*) vendor=stratus ;; esac ;; esac echo "$cpu-$vendor-${kernel:+$kernel-}$os" exit # Local variables: # eval: (add-hook 'before-save-hook 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: librecast/libs/000077500000000000000000000000001502456746400137745ustar00rootroot00000000000000librecast/libs/Makefile.in000066400000000000000000000011751502456746400160450ustar00rootroot00000000000000# SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only # Copyright (c) 2017-2023 Brett Sheffield SHELL = /bin/sh .SUFFIXES: TARGETS = TARGETS += @BLAKE3@ @MLD@ .PHONY: $(TARGETS) clean realclean update test all: $(TARGETS) $(TARGETS): $(MAKE) -C $@ test/mld: $(MAKE) -C libmld test memcheck/mld: $(MAKE) -C libmld memcheck clean update test: @for target in $(TARGETS); do \ echo "running tests for $$target"; \ $(MAKE) -C $$target $@; \ done realclean: clean @for target in $(TARGETS); do \ echo "running tests for $$target"; \ $(MAKE) -C $$target $@; \ done $(RM) Makefile check sanitize: librecast/libs/README.md000066400000000000000000000025031502456746400152530ustar00rootroot00000000000000# README - libs libmld is merged as a subtree. See [https://nuclearsquid.com/writings/subtree-merging-and-you/] and [https://www.atlassian.com/git/tutorials/git-subtree] ## Updating libmld To start from a fresh clone: ``` git clone git@codeberg.org:librecast/librecast.git cd librecast git remote add -f libmld git@codeberg.org:librecast/libmld.git git pull -s subtree libmld main ``` Once the remote is set up, to update: `git subtree pull --prefix libs/libmld libmld main --squash` This will create a squashed commit with a commit message listing the new upstream commits + a merge commit. NB: if local commits to the subtree have been made and pushed back upstream, doing this will try to pull these commits in again, resulting in conflicts. This can be avoided by editing the local commit and adding something like: ``` git-subtree-dir: libs/libmld git-subtree-split: dc7d0af181fb954b2a9a313a9e65c9729b2e5cc4 ``` where git-subtree-split points to the upstream commit hash. ## Pushing a local change to libmld back upstream `git subtree push --prefix=libs/libmld libmld main` ## subtree split The exact history of the subtree can be split out again, and all commit hashes will match the subproject. `git subtree split -P libs/libmld` This will output a single commit hash, which will be the latest commit in the subtree project. librecast/libs/blake3/000077500000000000000000000000001502456746400151355ustar00rootroot00000000000000librecast/libs/blake3/LICENSE000066400000000000000000000156101502456746400161450ustar00rootroot00000000000000Creative Commons Legal Code CC0 1.0 Universal CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED HEREUNDER. Statement of Purpose The laws of most jurisdictions throughout the world automatically confer exclusive Copyright and Related Rights (defined below) upon the creator and subsequent owner(s) (each and all, an "owner") of an original work of authorship and/or a database (each, a "Work"). Certain owners wish to permanently relinquish those rights to a Work for the purpose of contributing to a commons of creative, cultural and scientific works ("Commons") that the public can reliably and without fear of later claims of infringement build upon, modify, incorporate in other works, reuse and redistribute as freely as possible in any form whatsoever and for any purposes, including without limitation commercial purposes. These owners may contribute to the Commons to promote the ideal of a free culture and the further production of creative, cultural and scientific works, or to gain reputation or greater distribution for their Work in part through the use and efforts of others. For these and/or other purposes and motivations, and without any expectation of additional consideration or compensation, the person associating CC0 with a Work (the "Affirmer"), to the extent that he or she is an owner of Copyright and Related Rights in the Work, voluntarily elects to apply CC0 to the Work and publicly distribute the Work under its terms, with knowledge of his or her Copyright and Related Rights in the Work and the meaning and intended legal effect of CC0 on those rights. 1. Copyright and Related Rights. A Work made available under CC0 may be protected by copyright and related or neighboring rights ("Copyright and Related Rights"). Copyright and Related Rights include, but are not limited to, the following: i. the right to reproduce, adapt, distribute, perform, display, communicate, and translate a Work; ii. moral rights retained by the original author(s) and/or performer(s); iii. publicity and privacy rights pertaining to a person's image or likeness depicted in a Work; iv. rights protecting against unfair competition in regards to a Work, subject to the limitations in paragraph 4(a), below; v. rights protecting the extraction, dissemination, use and reuse of data in a Work; vi. database rights (such as those arising under Directive 96/9/EC of the European Parliament and of the Council of 11 March 1996 on the legal protection of databases, and under any national implementation thereof, including any amended or successor version of such directive); and vii. other similar, equivalent or corresponding rights throughout the world based on applicable law or treaty, and any national implementations thereof. 2. Waiver. To the greatest extent permitted by, but not in contravention of, applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and unconditionally waives, abandons, and surrenders all of Affirmer's Copyright and Related Rights and associated claims and causes of action, whether now known or unknown (including existing as well as future claims and causes of action), in the Work (i) in all territories worldwide, (ii) for the maximum duration provided by applicable law or treaty (including future time extensions), (iii) in any current or future medium and for any number of copies, and (iv) for any purpose whatsoever, including without limitation commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each member of the public at large and to the detriment of Affirmer's heirs and successors, fully intending that such Waiver shall not be subject to revocation, rescission, cancellation, termination, or any other legal or equitable action to disrupt the quiet enjoyment of the Work by the public as contemplated by Affirmer's express Statement of Purpose. 3. Public License Fallback. Should any part of the Waiver for any reason be judged legally invalid or ineffective under applicable law, then the Waiver shall be preserved to the maximum extent permitted taking into account Affirmer's express Statement of Purpose. In addition, to the extent the Waiver is so judged Affirmer hereby grants to each affected person a royalty-free, non transferable, non sublicensable, non exclusive, irrevocable and unconditional license to exercise Affirmer's Copyright and Related Rights in the Work (i) in all territories worldwide, (ii) for the maximum duration provided by applicable law or treaty (including future time extensions), (iii) in any current or future medium and for any number of copies, and (iv) for any purpose whatsoever, including without limitation commercial, advertising or promotional purposes (the "License"). The License shall be deemed effective as of the date CC0 was applied by Affirmer to the Work. Should any part of the License for any reason be judged legally invalid or ineffective under applicable law, such partial invalidity or ineffectiveness shall not invalidate the remainder of the License, and in such case Affirmer hereby affirms that he or she will not (i) exercise any of his or her remaining Copyright and Related Rights in the Work or (ii) assert any associated claims and causes of action with respect to the Work, in either case contrary to Affirmer's express Statement of Purpose. 4. Limitations and Disclaimers. a. No trademark or patent rights held by Affirmer are waived, abandoned, surrendered, licensed or otherwise affected by this document. b. Affirmer offers the Work as-is and makes no representations or warranties of any kind concerning the Work, express, implied, statutory or otherwise, including without limitation warranties of title, merchantability, fitness for a particular purpose, non infringement, or the absence of latent or other defects, accuracy, or the present or absence of errors, whether or not discoverable, all to the greatest extent permissible under applicable law. c. Affirmer disclaims responsibility for clearing rights of other persons that may apply to the Work or any use thereof, including without limitation any person's Copyright and Related Rights in the Work. Further, Affirmer disclaims responsibility for obtaining any necessary consents, permissions or other rights required for any use of the Work. d. Affirmer understands and acknowledges that Creative Commons is not a party to this document and has no duty or obligation with respect to this CC0 or use of the Work. librecast/libs/blake3/Makefile.in000066400000000000000000000006461502456746400172100ustar00rootroot00000000000000# SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only # Copyright (c) 2022-2024 Brett Sheffield SHELL = /bin/sh .SUFFIXES: SRC := ~/src/BLAKE3 FILES := LICENSE README.md .PHONY: all update clean realclean test all: $(MAKE) -C c $@ update: $(FILES) $(MAKE) -C c $@ test: LICENSE README.md: $(SRC)/$@ cp $(SRC)/$@ . clean: $(MAKE) -C c $@ realclean: clean $(MAKE) -C c $@ $(RM) Makefile librecast/libs/blake3/README.md000066400000000000000000000216151502456746400164210ustar00rootroot00000000000000# BLAKE3 BLAKE3 is a cryptographic hash function that is: - **Much faster** than MD5, SHA-1, SHA-2, SHA-3, and BLAKE2. - **Secure**, unlike MD5 and SHA-1. And secure against length extension, unlike SHA-2. - **Highly parallelizable** across any number of threads and SIMD lanes, because it's a Merkle tree on the inside. - Capable of **verified streaming** and **incremental updates**, again because it's a Merkle tree. - A **PRF**, **MAC**, **KDF**, and **XOF**, as well as a regular hash. - **One algorithm with no variants**, which is fast on x86-64 and also on smaller architectures. The [chart below](https://github.com/BLAKE3-team/BLAKE3-specs/blob/master/benchmarks/bar_chart.py) is an example benchmark of 16 KiB inputs on a Cascade Lake-SP 8275CL server CPU from 2019. For more detailed benchmarks, see the [BLAKE3 paper](https://github.com/BLAKE3-team/BLAKE3-specs/blob/master/blake3.pdf).

performance graph

BLAKE3 is based on an optimized instance of the established hash function [BLAKE2](https://blake2.net) and on the [original Bao tree mode](https://github.com/oconnor663/bao/blob/master/docs/spec_0.9.1.md). The specifications and design rationale are available in the [BLAKE3 paper](https://github.com/BLAKE3-team/BLAKE3-specs/blob/master/blake3.pdf). The default output size is 256 bits. The current version of [Bao](https://github.com/oconnor663/bao) implements verified streaming with BLAKE3. This repository is the official implementation of BLAKE3. It includes: * The [`blake3`](https://crates.io/crates/blake3) Rust crate, which includes optimized implementations for SSE2, SSE4.1, AVX2, AVX-512, and NEON, with automatic runtime CPU feature detection on x86. The `rayon` feature provides multithreading. * The [`b3sum`](https://crates.io/crates/b3sum) Rust crate, which provides a command line interface. It uses multithreading by default, making it an order of magnitude faster than e.g. `sha256sum` on typical desktop hardware. * The [C implementation](c), which like the Rust implementation includes SIMD code and runtime CPU feature detection on x86. Unlike the Rust implementation, it's [not currently multithreaded](c#multithreading). See [`c/README.md`](c/README.md). * The [Rust reference implementation](reference_impl/reference_impl.rs), which is discussed in Section 5.1 of the [BLAKE3 paper](https://github.com/BLAKE3-team/BLAKE3-specs/blob/master/blake3.pdf). This implementation is much smaller and simpler than the optimized ones above. If you want to see how BLAKE3 works, or you're writing a port that doesn't need multithreading or SIMD optimizations, start here. Ports of the reference implementation to other languages are hosted in separate repositories ([C](https://github.com/oconnor663/blake3_reference_impl_c), [Python](https://github.com/oconnor663/pure_python_blake3)). * A [set of test vectors](https://github.com/BLAKE3-team/BLAKE3/blob/master/test_vectors/test_vectors.json) that covers extended outputs, all three modes, and a variety of input lengths. * [![Actions Status](https://github.com/BLAKE3-team/BLAKE3/workflows/tests/badge.svg)](https://github.com/BLAKE3-team/BLAKE3/actions) BLAKE3 was designed by: * [@oconnor663 ](https://github.com/oconnor663) (Jack O'Connor) * [@sneves](https://github.com/sneves) (Samuel Neves) * [@veorq](https://github.com/veorq) (Jean-Philippe Aumasson) * [@zookozcash](https://github.com/zookozcash) (Zooko) The development of BLAKE3 was sponsored by [Electric Coin Company](https://electriccoin.co). *NOTE: BLAKE3 is not a password hashing algorithm, because it's designed to be fast, whereas password hashing should not be fast. If you hash passwords to store the hashes or if you derive keys from passwords, we recommend [Argon2](https://github.com/P-H-C/phc-winner-argon2).* ## Usage ### The `b3sum` utility The `b3sum` command line utility prints the BLAKE3 hashes of files or of standard input. Prebuilt binaries are available for Linux, Windows, and macOS (requiring the [unidentified developer workaround](https://support.apple.com/guide/mac-help/open-a-mac-app-from-an-unidentified-developer-mh40616/mac)) on the [releases page](https://github.com/BLAKE3-team/BLAKE3/releases). If you've [installed Rust and Cargo](https://doc.rust-lang.org/cargo/getting-started/installation.html), you can also build `b3sum` yourself with: ```bash cargo install b3sum ``` If `rustup` didn't configure your `PATH` for you, you might need to go looking for the installed binary in e.g. `~/.cargo/bin`. You can test out how fast BLAKE3 is on your machine by creating a big file and hashing it, for example: ```bash # Create a 1 GB file. head -c 1000000000 /dev/zero > /tmp/bigfile # Hash it with SHA-256. time openssl sha256 /tmp/bigfile # Hash it with BLAKE3. time b3sum /tmp/bigfile ``` ### The `blake3` crate [![docs.rs](https://docs.rs/blake3/badge.svg)](https://docs.rs/blake3) To use BLAKE3 from Rust code, add a dependency on the `blake3` crate to your `Cargo.toml`. Here's an example of hashing some input bytes: ```rust // Hash an input all at once. let hash1 = blake3::hash(b"foobarbaz"); // Hash an input incrementally. let mut hasher = blake3::Hasher::new(); hasher.update(b"foo"); hasher.update(b"bar"); hasher.update(b"baz"); let hash2 = hasher.finalize(); assert_eq!(hash1, hash2); // Extended output. OutputReader also implements Read and Seek. let mut output = [0; 1000]; let mut output_reader = hasher.finalize_xof(); output_reader.fill(&mut output); assert_eq!(hash1, output[..32]); // Print a hash as hex. println!("{}", hash1); ``` Besides `hash`, BLAKE3 provides two other modes, `keyed_hash` and `derive_key`. The `keyed_hash` mode takes a 256-bit key: ```rust // MAC an input all at once. let example_key = [42u8; 32]; let mac1 = blake3::keyed_hash(&example_key, b"example input"); // MAC incrementally. let mut hasher = blake3::Hasher::new_keyed(&example_key); hasher.update(b"example input"); let mac2 = hasher.finalize(); assert_eq!(mac1, mac2); ``` The `derive_key` mode takes a context string and some key material (not a password). The context string should be hardcoded, globally unique, and application-specific. A good default format for the context string is `"[application] [commit timestamp] [purpose]"`: ```rust // Derive a couple of subkeys for different purposes. const EMAIL_CONTEXT: &str = "BLAKE3 example 2020-01-07 17:10:44 email key"; const API_CONTEXT: &str = "BLAKE3 example 2020-01-07 17:11:21 API key"; let input_key_material = b"usually at least 32 random bytes, not a password"; let email_key = blake3::derive_key(EMAIL_CONTEXT, input_key_material); let api_key = blake3::derive_key(API_CONTEXT, input_key_material); assert_ne!(email_key, api_key); ``` ### The C implementation See [`c/README.md`](c/README.md). ### Other implementations We post links to third-party bindings and implementations on the [@BLAKE3team Twitter account](https://twitter.com/BLAKE3team) whenever we hear about them. Some highlights include [an optimized Go implementation](https://github.com/zeebo/blake3), [Wasm bindings for Node.js and browsers](https://github.com/connor4312/blake3), [binary wheels for Python](https://github.com/oconnor663/blake3-py), [.NET bindings](https://github.com/xoofx/Blake3.NET), and [JNI bindings](https://github.com/sken77/BLAKE3jni). ## Contributing Please see [CONTRIBUTING.md](CONTRIBUTING.md). ## Licenses This work is released into the public domain with [CC0 1.0](./LICENSE_CC0). Alternatively, it is licensed under any of the following: * [Apache 2.0](./LICENSE_A2) * [Apache 2.0 with LLVM exceptions](./LICENSE_A2LLVM) ## Adoption & deployment Here's a (non-exhaustive) list of protocols and software that use BLAKE3: * [Alephium](https://github.com/alephium/alephium/blob/master/crypto/src/main/scala/org/alephium/crypto/Blake3.scala) * [Bazel](https://github.com/bazelbuild/bazel/releases/tag/6.4.0) * [Chia](https://github.com/Chia-Network/chia-blockchain/blob/main/CHANGELOG.md#10beta8-aka-beta-18---2020-07-16) * [IPFS](https://github.com/ipfs/go-verifcid/issues/13) * [Farcaster](https://www.farcaster.xyz/) * [LLVM](https://reviews.llvm.org/D121510) * [Nym](https://github.com/nymtech/nym/blob/59056a22c5e6b01a38da2124662bd1fa3c8abef2/common/nymsphinx/params/src/lib.rs#L5) * [OpenZFS](https://github.com/openzfs/zfs/) * [Redox](https://www.redox-os.org/news/pkgar-introduction/) * [Saito](https://saito.tech/) * [Skale](https://github.com/skalenetwork/skale-consensus/pull/284) * [Solana](https://docs.rs/solana-program/1.9.5/solana_program/blake3/index.html) * [Tekken 8](https://en.bandainamcoent.eu/tekken/tekken-8) * [Wasmer](https://github.com/wasmerio/wasmer/blob/4f935a8c162bf604df223003e434e4f7ca253688/lib/cache/src/hash.rs#L21) ## Miscellany - [@veorq](https://github.com/veorq) and [@oconnor663](https://github.com/oconnor663) did [a podcast interview](https://www.cryptography.fm/3) about designing BLAKE3. librecast/libs/blake3/c/000077500000000000000000000000001502456746400153575ustar00rootroot00000000000000librecast/libs/blake3/c/.gitignore000066400000000000000000000000751502456746400173510ustar00rootroot00000000000000blake3 example example_tbb build/ *.o CMakeUserPresets.json librecast/libs/blake3/c/Makefile.in000066400000000000000000000015321502456746400174250ustar00rootroot00000000000000# SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only # Copyright (c) 2022 Brett Sheffield SHELL = /bin/sh .SUFFIXES: .SUFFIXES: .c .o .asm .S SRC := ~/src/BLAKE3 ASMFILES := $(notdir $(wildcard $(SRC)/c/*.asm)) CFILES := $(notdir $(wildcard $(SRC)/c/*.c)) HFILES := $(notdir $(wildcard $(SRC)/c/*.h)) SFILES := $(notdir $(wildcard $(SRC)/c/*.S)) FILES := $(ASMFILES) $(CFILES) $(HFILES) $(SFILES) CFLAGS += -fPIC -DBLAKE3_NO_SSE2 -DBLAKE3_NO_SSE41 -DBLAKE3_NO_AVX2 -DBLAKE3_NO_AVX512 -DBLAKE3_USE_NEON=0 .PHONY: clean realclean all: libblake3.a update: $(FILES) %.asm: $(SRC)/c/%.asm cp $^ $@ %.c: $(SRC)/c/%.c cp $^ $@ %.h: $(SRC)/c/%.h cp $^ $@ %.S: $(SRC)/c/%.S cp $^ $@ libblake3.a: blake3.o blake3_dispatch.o blake3_portable.o $(AR) rcs $@ $^ clean: $(RM) *.o realclean: clean $(RM) libblake3.a $(RM) Makefile librecast/libs/blake3/c/Makefile.testing000066400000000000000000000040111502456746400204670ustar00rootroot00000000000000# This Makefile is only for testing. C callers should follow the instructions # in ./README.md to incorporate these C files into their existing build. NAME=blake3 CC=gcc CFLAGS=-O3 -Wall -Wextra -std=c11 -pedantic -fstack-protector-strong -D_FORTIFY_SOURCE=2 -fPIE -fvisibility=hidden LDFLAGS=-pie -Wl,-z,relro,-z,now TARGETS= ASM_TARGETS= EXTRAFLAGS=-Wa,--noexecstack ifdef BLAKE3_NO_SSE2 EXTRAFLAGS += -DBLAKE3_NO_SSE2 else TARGETS += blake3_sse2.o ASM_TARGETS += blake3_sse2_x86-64_unix.S endif ifdef BLAKE3_NO_SSE41 EXTRAFLAGS += -DBLAKE3_NO_SSE41 else TARGETS += blake3_sse41.o ASM_TARGETS += blake3_sse41_x86-64_unix.S endif ifdef BLAKE3_NO_AVX2 EXTRAFLAGS += -DBLAKE3_NO_AVX2 else TARGETS += blake3_avx2.o ASM_TARGETS += blake3_avx2_x86-64_unix.S endif ifdef BLAKE3_NO_AVX512 EXTRAFLAGS += -DBLAKE3_NO_AVX512 else TARGETS += blake3_avx512.o ASM_TARGETS += blake3_avx512_x86-64_unix.S endif ifdef BLAKE3_USE_NEON EXTRAFLAGS += -DBLAKE3_USE_NEON=1 TARGETS += blake3_neon.o endif ifdef BLAKE3_NO_NEON EXTRAFLAGS += -DBLAKE3_USE_NEON=0 endif all: blake3.c blake3_dispatch.c blake3_portable.c main.c $(TARGETS) $(CC) $(CFLAGS) $(EXTRAFLAGS) $^ -o $(NAME) $(LDFLAGS) blake3_sse2.o: blake3_sse2.c $(CC) $(CFLAGS) $(EXTRAFLAGS) -c $^ -o $@ -msse2 blake3_sse41.o: blake3_sse41.c $(CC) $(CFLAGS) $(EXTRAFLAGS) -c $^ -o $@ -msse4.1 blake3_avx2.o: blake3_avx2.c $(CC) $(CFLAGS) $(EXTRAFLAGS) -c $^ -o $@ -mavx2 blake3_avx512.o: blake3_avx512.c $(CC) $(CFLAGS) $(EXTRAFLAGS) -c $^ -o $@ -mavx512f -mavx512vl blake3_neon.o: blake3_neon.c $(CC) $(CFLAGS) $(EXTRAFLAGS) -c $^ -o $@ test: CFLAGS += -DBLAKE3_TESTING -fsanitize=address,undefined test: all ./test.py asm: blake3.c blake3_dispatch.c blake3_portable.c main.c $(ASM_TARGETS) $(CC) $(CFLAGS) $(EXTRAFLAGS) $^ -o $(NAME) $(LDFLAGS) test_asm: CFLAGS += -DBLAKE3_TESTING -fsanitize=address,undefined test_asm: asm ./test.py example: example.c blake3.c blake3_dispatch.c blake3_portable.c $(ASM_TARGETS) $(CC) $(CFLAGS) $(EXTRAFLAGS) $^ -o $@ $(LDFLAGS) clean: rm -f $(NAME) *.o librecast/libs/blake3/c/README.md000066400000000000000000000325141502456746400166430ustar00rootroot00000000000000The official C implementation of BLAKE3. # Example An example program that hashes bytes from standard input and prints the result: ```c #include "blake3.h" #include #include #include #include int main(void) { // Initialize the hasher. blake3_hasher hasher; blake3_hasher_init(&hasher); // Read input bytes from stdin. unsigned char buf[65536]; while (1) { ssize_t n = read(STDIN_FILENO, buf, sizeof(buf)); if (n > 0) { blake3_hasher_update(&hasher, buf, n); } else if (n == 0) { break; // end of file } else { fprintf(stderr, "read failed: %s\n", strerror(errno)); return 1; } } // Finalize the hash. BLAKE3_OUT_LEN is the default output length, 32 bytes. uint8_t output[BLAKE3_OUT_LEN]; blake3_hasher_finalize(&hasher, output, BLAKE3_OUT_LEN); // Print the hash as hexadecimal. for (size_t i = 0; i < BLAKE3_OUT_LEN; i++) { printf("%02x", output[i]); } printf("\n"); return 0; } ``` The code above is included in this directory as `example.c`. If you're on x86\_64 with a Unix-like OS, you can compile a working binary like this: ```bash gcc -O3 -o example example.c blake3.c blake3_dispatch.c blake3_portable.c \ blake3_sse2_x86-64_unix.S blake3_sse41_x86-64_unix.S blake3_avx2_x86-64_unix.S \ blake3_avx512_x86-64_unix.S ``` # API ## The Struct ```c typedef struct { // private fields } blake3_hasher; ``` An incremental BLAKE3 hashing state, which can accept any number of updates. This implementation doesn't allocate any heap memory, but `sizeof(blake3_hasher)` itself is relatively large, currently 1912 bytes on x86-64. This size can be reduced by restricting the maximum input length, as described in Section 5.4 of [the BLAKE3 spec](https://github.com/BLAKE3-team/BLAKE3-specs/blob/master/blake3.pdf), but this implementation doesn't currently support that strategy. ## Common API Functions ```c void blake3_hasher_init( blake3_hasher *self); ``` Initialize a `blake3_hasher` in the default hashing mode. --- ```c void blake3_hasher_update( blake3_hasher *self, const void *input, size_t input_len); ``` Add input to the hasher. This can be called any number of times. This function is always single-threaded; for multithreading see `blake3_hasher_update_tbb` below. --- ```c void blake3_hasher_finalize( const blake3_hasher *self, uint8_t *out, size_t out_len); ``` Finalize the hasher and return an output of any length, given in bytes. This doesn't modify the hasher itself, and it's possible to finalize again after adding more input. The constant `BLAKE3_OUT_LEN` provides the default output length, 32 bytes, which is recommended for most callers. See the [Security Notes](#security-notes) below. ## Less Common API Functions ```c void blake3_hasher_init_keyed( blake3_hasher *self, const uint8_t key[BLAKE3_KEY_LEN]); ``` Initialize a `blake3_hasher` in the keyed hashing mode. The key must be exactly 32 bytes. --- ```c void blake3_hasher_init_derive_key( blake3_hasher *self, const char *context); ``` Initialize a `blake3_hasher` in the key derivation mode. The context string is given as an initialization parameter, and afterwards input key material should be given with `blake3_hasher_update`. The context string is a null-terminated C string which should be **hardcoded, globally unique, and application-specific**. The context string should not include any dynamic input like salts, nonces, or identifiers read from a database at runtime. A good default format for the context string is `"[application] [commit timestamp] [purpose]"`, e.g., `"example.com 2019-12-25 16:18:03 session tokens v1"`. This function is intended for application code written in C. For language bindings, see `blake3_hasher_init_derive_key_raw` below. --- ```c void blake3_hasher_init_derive_key_raw( blake3_hasher *self, const void *context, size_t context_len); ``` As `blake3_hasher_init_derive_key` above, except that the context string is given as a pointer to an array of arbitrary bytes with a provided length. This is intended for writing language bindings, where C string conversion would add unnecessary overhead and new error cases. Unicode strings should be encoded as UTF-8. Application code in C should prefer `blake3_hasher_init_derive_key`, which takes the context as a C string. If you need to use arbitrary bytes as a context string in application code, consider whether you're violating the requirement that context strings should be hardcoded. --- ```c void blake3_hasher_update_tbb( blake3_hasher *self, const void *input, size_t input_len); ``` Add input to the hasher, using [oneTBB] to process large inputs using multiple threads. This can be called any number of times. This gives the same result as `blake3_hasher_update` above. [oneTBB]: https://uxlfoundation.github.io/oneTBB/ NOTE: This function is only enabled when the library is compiled with CMake option `BLAKE3_USE_TBB` and when the oneTBB library is detected on the host system. See the building instructions for further details. To get any performance benefit from multithreading, the input buffer needs to be large. As a rule of thumb on x86_64, `blake3_hasher_update_tbb` is _slower_ than `blake3_hasher_update` for inputs under 128 KiB. That threshold varies quite a lot across different processors, and it's important to benchmark your specific use case. Hashing large files with this function usually requires [memory-mapping](https://en.wikipedia.org/wiki/Memory-mapped_file), since reading a file into memory in a single-threaded loop takes longer than hashing the resulting buffer. Note that hashing a memory-mapped file with this function produces a "random" pattern of disk reads, which can be slow on spinning disks. Again it's important to benchmark your specific use case. This implementation doesn't require configuration of thread resources and will use as many cores as possible by default. More fine-grained control of resources is possible using the [oneTBB] API. --- ```c void blake3_hasher_finalize_seek( const blake3_hasher *self, uint64_t seek, uint8_t *out, size_t out_len); ``` The same as `blake3_hasher_finalize`, but with an additional `seek` parameter for the starting byte position in the output stream. To efficiently stream a large output without allocating memory, call this function in a loop, incrementing `seek` by the output length each time. --- ```c void blake3_hasher_reset( blake3_hasher *self); ``` Reset the hasher to its initial state, prior to any calls to `blake3_hasher_update`. Currently this is no different from calling `blake3_hasher_init` or similar again. # Security Notes Outputs shorter than the default length of 32 bytes (256 bits) provide less security. An N-bit BLAKE3 output is intended to provide N bits of first and second preimage resistance and N/2 bits of collision resistance, for any N up to 256. Longer outputs don't provide any additional security. Avoid relying on the secrecy of the output offset, that is, the `seek` argument of `blake3_hasher_finalize_seek`. [_Block-Cipher-Based Tree Hashing_ by Aldo Gunsing](https://eprint.iacr.org/2022/283) shows that an attacker who knows both the message and the key (if any) can easily determine the offset of an extended output. For comparison, AES-CTR has a similar property: if you know the key, you can decrypt a block from an unknown position in the output stream to recover its block index. Callers with strong secret keys aren't affected in practice, but secret offsets are a [design smell](https://en.wikipedia.org/wiki/Design_smell) in any case. # Building The easiest and most complete method of compiling this library is with CMake. This is the method described in the next section. Toward the end of the building section there are more in depth notes about compiling manually and things that are useful to understand if you need to integrate this library with another build system. ## CMake The minimum version of CMake is 3.9. The following invocations will compile and install `libblake3`. With recent CMake: ```bash cmake -S c -B c/build "-DCMAKE_INSTALL_PREFIX=/usr/local" cmake --build c/build --target install ``` With an older CMake: ```bash cd c mkdir build cd build cmake .. "-DCMAKE_INSTALL_PREFIX=/usr/local" cmake --build . --target install ``` The following options are available when compiling with CMake: - `BLAKE3_USE_TBB`: Enable oneTBB parallelism (Requires a C++20 capable compiler) - `BLAKE3_FETCH_TBB`: Allow fetching oneTBB from GitHub (only if not found on system) - `BLAKE3_EXAMPLES`: Compile and install example programs Options can be enabled like this: ```bash cmake -S c -B c/build "-DCMAKE_INSTALL_PREFIX=/usr/local" -DCMAKE_USE_TBB=1 -DCMAKE_FETCH_TBB=1 ``` ## Building manually We try to keep the build simple enough that you can compile this library "by hand", and it's expected that many callers will integrate it with their pre-existing build systems. See the `gcc` one-liner in the "Example" section above. ### x86 Dynamic dispatch is enabled by default on x86. The implementation will query the CPU at runtime to detect SIMD support, and it will use the widest instruction set available. By default, `blake3_dispatch.c` expects to be linked with code for five different instruction sets: portable C, SSE2, SSE4.1, AVX2, and AVX-512. For each of the x86 SIMD instruction sets, four versions are available: three flavors of assembly (Unix, Windows MSVC, and Windows GNU) and one version using C intrinsics. The assembly versions are generally preferred. They perform better, they perform more consistently across different compilers, and they build more quickly. On the other hand, the assembly versions are x86\_64-only, and you need to select the right flavor for your target platform. Here's an example of building a shared library on x86\_64 Linux using the assembly implementations: ```bash gcc -shared -O3 -o libblake3.so blake3.c blake3_dispatch.c blake3_portable.c \ blake3_sse2_x86-64_unix.S blake3_sse41_x86-64_unix.S blake3_avx2_x86-64_unix.S \ blake3_avx512_x86-64_unix.S ``` When building the intrinsics-based implementations, you need to build each implementation separately, with the corresponding instruction set explicitly enabled in the compiler. Here's the same shared library using the intrinsics-based implementations: ```bash gcc -c -fPIC -O3 -msse2 blake3_sse2.c -o blake3_sse2.o gcc -c -fPIC -O3 -msse4.1 blake3_sse41.c -o blake3_sse41.o gcc -c -fPIC -O3 -mavx2 blake3_avx2.c -o blake3_avx2.o gcc -c -fPIC -O3 -mavx512f -mavx512vl blake3_avx512.c -o blake3_avx512.o gcc -shared -O3 -o libblake3.so blake3.c blake3_dispatch.c blake3_portable.c \ blake3_avx2.o blake3_avx512.o blake3_sse41.o blake3_sse2.o ``` Note above that building `blake3_avx512.c` requires both `-mavx512f` and `-mavx512vl` under GCC and Clang. Under MSVC, the single `/arch:AVX512` flag is sufficient. The MSVC equivalent of `-mavx2` is `/arch:AVX2`. MSVC enables SSE2 and SSE4.1 by default, and it doesn't have a corresponding flag. If you want to omit SIMD code entirely, you need to explicitly disable each instruction set. Here's an example of building a shared library on x86 with only portable code: ```bash gcc -shared -O3 -o libblake3.so -DBLAKE3_NO_SSE2 -DBLAKE3_NO_SSE41 -DBLAKE3_NO_AVX2 \ -DBLAKE3_NO_AVX512 blake3.c blake3_dispatch.c blake3_portable.c ``` ### ARM NEON The NEON implementation is enabled by default on AArch64, but not on other ARM targets, since not all of them support it. To enable it, set `BLAKE3_USE_NEON=1`. Here's an example of building a shared library on ARM Linux with NEON support: ```bash gcc -shared -O3 -o libblake3.so -DBLAKE3_USE_NEON=1 blake3.c blake3_dispatch.c \ blake3_portable.c blake3_neon.c ``` To explicitiy disable using NEON instructions on AArch64, set `BLAKE3_USE_NEON=0`. ```bash gcc -shared -O3 -o libblake3.so -DBLAKE3_USE_NEON=0 blake3.c blake3_dispatch.c \ blake3_portable.c ``` Note that on some targets (ARMv7 in particular), extra flags may be required to activate NEON support in the compiler. If you see an error like... ``` /usr/lib/gcc/armv7l-unknown-linux-gnueabihf/9.2.0/include/arm_neon.h:635:1: error: inlining failed in call to always_inline ‘vaddq_u32’: target specific option mismatch ``` ...then you may need to add something like `-mfpu=neon-vfpv4 -mfloat-abi=hard`. ### Other Platforms The portable implementation should work on most other architectures. For example: ```bash gcc -shared -O3 -o libblake3.so blake3.c blake3_dispatch.c blake3_portable.c ``` ### Multithreading Multithreading is available using [oneTBB], by compiling the optional C++ support file [`blake3_tbb.cpp`](./blake3_tbb.cpp). For an example of using `mmap` (non-Windows) and `blake3_hasher_update_tbb` to get large-file performance on par with [`b3sum`](../b3sum), see [`example_tbb.c`](./example_tbb.c). You can build it like this: ```bash g++ -c -O3 -fno-exceptions -fno-rtti -DBLAKE3_USE_TBB -o blake3_tbb.o blake3_tbb.cpp gcc -O3 -o example_tbb -lstdc++ -ltbb -DBLAKE3_USE_TBB blake3_tbb.o example_tbb.c blake3.c \ blake3_dispatch.c blake3_portable.c blake3_sse2_x86-64_unix.S blake3_sse41_x86-64_unix.S \ blake3_avx2_x86-64_unix.S blake3_avx512_x86-64_unix.S ``` NOTE: `-fno-exceptions` or equivalent is required to compile `blake3_tbb.cpp`, and public API methods with external C linkage are marked `noexcept`. Compiling that file with exceptions enabled will fail. Compiling with RTTI disabled isn't required but is recommended for code size. librecast/libs/blake3/c/blake3.c000066400000000000000000000703471502456746400166770ustar00rootroot00000000000000#include #include #include #include "blake3.h" #include "blake3_impl.h" const char *blake3_version(void) { return BLAKE3_VERSION_STRING; } INLINE void chunk_state_init(blake3_chunk_state *self, const uint32_t key[8], uint8_t flags) { memcpy(self->cv, key, BLAKE3_KEY_LEN); self->chunk_counter = 0; memset(self->buf, 0, BLAKE3_BLOCK_LEN); self->buf_len = 0; self->blocks_compressed = 0; self->flags = flags; } INLINE void chunk_state_reset(blake3_chunk_state *self, const uint32_t key[8], uint64_t chunk_counter) { memcpy(self->cv, key, BLAKE3_KEY_LEN); self->chunk_counter = chunk_counter; self->blocks_compressed = 0; memset(self->buf, 0, BLAKE3_BLOCK_LEN); self->buf_len = 0; } INLINE size_t chunk_state_len(const blake3_chunk_state *self) { return (BLAKE3_BLOCK_LEN * (size_t)self->blocks_compressed) + ((size_t)self->buf_len); } INLINE size_t chunk_state_fill_buf(blake3_chunk_state *self, const uint8_t *input, size_t input_len) { size_t take = BLAKE3_BLOCK_LEN - ((size_t)self->buf_len); if (take > input_len) { take = input_len; } uint8_t *dest = self->buf + ((size_t)self->buf_len); memcpy(dest, input, take); self->buf_len += (uint8_t)take; return take; } INLINE uint8_t chunk_state_maybe_start_flag(const blake3_chunk_state *self) { if (self->blocks_compressed == 0) { return CHUNK_START; } else { return 0; } } typedef struct { uint32_t input_cv[8]; uint64_t counter; uint8_t block[BLAKE3_BLOCK_LEN]; uint8_t block_len; uint8_t flags; } output_t; INLINE output_t make_output(const uint32_t input_cv[8], const uint8_t block[BLAKE3_BLOCK_LEN], uint8_t block_len, uint64_t counter, uint8_t flags) { output_t ret; memcpy(ret.input_cv, input_cv, 32); memcpy(ret.block, block, BLAKE3_BLOCK_LEN); ret.block_len = block_len; ret.counter = counter; ret.flags = flags; return ret; } // Chaining values within a given chunk (specifically the compress_in_place // interface) are represented as words. This avoids unnecessary bytes<->words // conversion overhead in the portable implementation. However, the hash_many // interface handles both user input and parent node blocks, so it accepts // bytes. For that reason, chaining values in the CV stack are represented as // bytes. INLINE void output_chaining_value(const output_t *self, uint8_t cv[32]) { uint32_t cv_words[8]; memcpy(cv_words, self->input_cv, 32); blake3_compress_in_place(cv_words, self->block, self->block_len, self->counter, self->flags); store_cv_words(cv, cv_words); } INLINE void output_root_bytes(const output_t *self, uint64_t seek, uint8_t *out, size_t out_len) { if (out_len == 0) { return; } uint64_t output_block_counter = seek / 64; size_t offset_within_block = seek % 64; uint8_t wide_buf[64]; if(offset_within_block) { blake3_compress_xof(self->input_cv, self->block, self->block_len, output_block_counter, self->flags | ROOT, wide_buf); const size_t available_bytes = 64 - offset_within_block; const size_t bytes = out_len > available_bytes ? available_bytes : out_len; memcpy(out, wide_buf + offset_within_block, bytes); out += bytes; out_len -= bytes; output_block_counter += 1; } if(out_len / 64) { blake3_xof_many(self->input_cv, self->block, self->block_len, output_block_counter, self->flags | ROOT, out, out_len / 64); } output_block_counter += out_len / 64; out += out_len & -64; out_len -= out_len & -64; if(out_len) { blake3_compress_xof(self->input_cv, self->block, self->block_len, output_block_counter, self->flags | ROOT, wide_buf); memcpy(out, wide_buf, out_len); } } INLINE void chunk_state_update(blake3_chunk_state *self, const uint8_t *input, size_t input_len) { if (self->buf_len > 0) { size_t take = chunk_state_fill_buf(self, input, input_len); input += take; input_len -= take; if (input_len > 0) { blake3_compress_in_place( self->cv, self->buf, BLAKE3_BLOCK_LEN, self->chunk_counter, self->flags | chunk_state_maybe_start_flag(self)); self->blocks_compressed += 1; self->buf_len = 0; memset(self->buf, 0, BLAKE3_BLOCK_LEN); } } while (input_len > BLAKE3_BLOCK_LEN) { blake3_compress_in_place(self->cv, input, BLAKE3_BLOCK_LEN, self->chunk_counter, self->flags | chunk_state_maybe_start_flag(self)); self->blocks_compressed += 1; input += BLAKE3_BLOCK_LEN; input_len -= BLAKE3_BLOCK_LEN; } chunk_state_fill_buf(self, input, input_len); } INLINE output_t chunk_state_output(const blake3_chunk_state *self) { uint8_t block_flags = self->flags | chunk_state_maybe_start_flag(self) | CHUNK_END; return make_output(self->cv, self->buf, self->buf_len, self->chunk_counter, block_flags); } INLINE output_t parent_output(const uint8_t block[BLAKE3_BLOCK_LEN], const uint32_t key[8], uint8_t flags) { return make_output(key, block, BLAKE3_BLOCK_LEN, 0, flags | PARENT); } // Given some input larger than one chunk, return the number of bytes that // should go in the left subtree. This is the largest power-of-2 number of // chunks that leaves at least 1 byte for the right subtree. INLINE size_t left_len(size_t content_len) { // Subtract 1 to reserve at least one byte for the right side. content_len // should always be greater than BLAKE3_CHUNK_LEN. size_t full_chunks = (content_len - 1) / BLAKE3_CHUNK_LEN; return round_down_to_power_of_2(full_chunks) * BLAKE3_CHUNK_LEN; } // Use SIMD parallelism to hash up to MAX_SIMD_DEGREE chunks at the same time // on a single thread. Write out the chunk chaining values and return the // number of chunks hashed. These chunks are never the root and never empty; // those cases use a different codepath. INLINE size_t compress_chunks_parallel(const uint8_t *input, size_t input_len, const uint32_t key[8], uint64_t chunk_counter, uint8_t flags, uint8_t *out) { #if defined(BLAKE3_TESTING) assert(0 < input_len); assert(input_len <= MAX_SIMD_DEGREE * BLAKE3_CHUNK_LEN); #endif const uint8_t *chunks_array[MAX_SIMD_DEGREE]; size_t input_position = 0; size_t chunks_array_len = 0; while (input_len - input_position >= BLAKE3_CHUNK_LEN) { chunks_array[chunks_array_len] = &input[input_position]; input_position += BLAKE3_CHUNK_LEN; chunks_array_len += 1; } blake3_hash_many(chunks_array, chunks_array_len, BLAKE3_CHUNK_LEN / BLAKE3_BLOCK_LEN, key, chunk_counter, true, flags, CHUNK_START, CHUNK_END, out); // Hash the remaining partial chunk, if there is one. Note that the empty // chunk (meaning the empty message) is a different codepath. if (input_len > input_position) { uint64_t counter = chunk_counter + (uint64_t)chunks_array_len; blake3_chunk_state chunk_state; chunk_state_init(&chunk_state, key, flags); chunk_state.chunk_counter = counter; chunk_state_update(&chunk_state, &input[input_position], input_len - input_position); output_t output = chunk_state_output(&chunk_state); output_chaining_value(&output, &out[chunks_array_len * BLAKE3_OUT_LEN]); return chunks_array_len + 1; } else { return chunks_array_len; } } // Use SIMD parallelism to hash up to MAX_SIMD_DEGREE parents at the same time // on a single thread. Write out the parent chaining values and return the // number of parents hashed. (If there's an odd input chaining value left over, // return it as an additional output.) These parents are never the root and // never empty; those cases use a different codepath. INLINE size_t compress_parents_parallel(const uint8_t *child_chaining_values, size_t num_chaining_values, const uint32_t key[8], uint8_t flags, uint8_t *out) { #if defined(BLAKE3_TESTING) assert(2 <= num_chaining_values); assert(num_chaining_values <= 2 * MAX_SIMD_DEGREE_OR_2); #endif const uint8_t *parents_array[MAX_SIMD_DEGREE_OR_2]; size_t parents_array_len = 0; while (num_chaining_values - (2 * parents_array_len) >= 2) { parents_array[parents_array_len] = &child_chaining_values[2 * parents_array_len * BLAKE3_OUT_LEN]; parents_array_len += 1; } blake3_hash_many(parents_array, parents_array_len, 1, key, 0, // Parents always use counter 0. false, flags | PARENT, 0, // Parents have no start flags. 0, // Parents have no end flags. out); // If there's an odd child left over, it becomes an output. if (num_chaining_values > 2 * parents_array_len) { memcpy(&out[parents_array_len * BLAKE3_OUT_LEN], &child_chaining_values[2 * parents_array_len * BLAKE3_OUT_LEN], BLAKE3_OUT_LEN); return parents_array_len + 1; } else { return parents_array_len; } } // The wide helper function returns (writes out) an array of chaining values // and returns the length of that array. The number of chaining values returned // is the dynamically detected SIMD degree, at most MAX_SIMD_DEGREE. Or fewer, // if the input is shorter than that many chunks. The reason for maintaining a // wide array of chaining values going back up the tree, is to allow the // implementation to hash as many parents in parallel as possible. // // As a special case when the SIMD degree is 1, this function will still return // at least 2 outputs. This guarantees that this function doesn't perform the // root compression. (If it did, it would use the wrong flags, and also we // wouldn't be able to implement extendable output.) Note that this function is // not used when the whole input is only 1 chunk long; that's a different // codepath. // // Why not just have the caller split the input on the first update(), instead // of implementing this special rule? Because we don't want to limit SIMD or // multi-threading parallelism for that update(). size_t blake3_compress_subtree_wide(const uint8_t *input, size_t input_len, const uint32_t key[8], uint64_t chunk_counter, uint8_t flags, uint8_t *out, bool use_tbb) { // Note that the single chunk case does *not* bump the SIMD degree up to 2 // when it is 1. If this implementation adds multi-threading in the future, // this gives us the option of multi-threading even the 2-chunk case, which // can help performance on smaller platforms. if (input_len <= blake3_simd_degree() * BLAKE3_CHUNK_LEN) { return compress_chunks_parallel(input, input_len, key, chunk_counter, flags, out); } // With more than simd_degree chunks, we need to recurse. Start by dividing // the input into left and right subtrees. (Note that this is only optimal // as long as the SIMD degree is a power of 2. If we ever get a SIMD degree // of 3 or something, we'll need a more complicated strategy.) size_t left_input_len = left_len(input_len); size_t right_input_len = input_len - left_input_len; const uint8_t *right_input = &input[left_input_len]; uint64_t right_chunk_counter = chunk_counter + (uint64_t)(left_input_len / BLAKE3_CHUNK_LEN); // Make space for the child outputs. Here we use MAX_SIMD_DEGREE_OR_2 to // account for the special case of returning 2 outputs when the SIMD degree // is 1. uint8_t cv_array[2 * MAX_SIMD_DEGREE_OR_2 * BLAKE3_OUT_LEN]; size_t degree = blake3_simd_degree(); if (left_input_len > BLAKE3_CHUNK_LEN && degree == 1) { // The special case: We always use a degree of at least two, to make // sure there are two outputs. Except, as noted above, at the chunk // level, where we allow degree=1. (Note that the 1-chunk-input case is // a different codepath.) degree = 2; } uint8_t *right_cvs = &cv_array[degree * BLAKE3_OUT_LEN]; // Recurse! size_t left_n = -1; size_t right_n = -1; #if defined(BLAKE3_USE_TBB) blake3_compress_subtree_wide_join_tbb( key, flags, use_tbb, // left-hand side input, left_input_len, chunk_counter, cv_array, &left_n, // right-hand side right_input, right_input_len, right_chunk_counter, right_cvs, &right_n); #else left_n = blake3_compress_subtree_wide( input, left_input_len, key, chunk_counter, flags, cv_array, use_tbb); right_n = blake3_compress_subtree_wide(right_input, right_input_len, key, right_chunk_counter, flags, right_cvs, use_tbb); #endif // BLAKE3_USE_TBB // The special case again. If simd_degree=1, then we'll have left_n=1 and // right_n=1. Rather than compressing them into a single output, return // them directly, to make sure we always have at least two outputs. if (left_n == 1) { memcpy(out, cv_array, 2 * BLAKE3_OUT_LEN); return 2; } // Otherwise, do one layer of parent node compression. size_t num_chaining_values = left_n + right_n; return compress_parents_parallel(cv_array, num_chaining_values, key, flags, out); } // Hash a subtree with compress_subtree_wide(), and then condense the resulting // list of chaining values down to a single parent node. Don't compress that // last parent node, however. Instead, return its message bytes (the // concatenated chaining values of its children). This is necessary when the // first call to update() supplies a complete subtree, because the topmost // parent node of that subtree could end up being the root. It's also necessary // for extended output in the general case. // // As with compress_subtree_wide(), this function is not used on inputs of 1 // chunk or less. That's a different codepath. INLINE void compress_subtree_to_parent_node(const uint8_t *input, size_t input_len, const uint32_t key[8], uint64_t chunk_counter, uint8_t flags, uint8_t out[2 * BLAKE3_OUT_LEN], bool use_tbb) { #if defined(BLAKE3_TESTING) assert(input_len > BLAKE3_CHUNK_LEN); #endif uint8_t cv_array[MAX_SIMD_DEGREE_OR_2 * BLAKE3_OUT_LEN]; size_t num_cvs = blake3_compress_subtree_wide(input, input_len, key, chunk_counter, flags, cv_array, use_tbb); assert(num_cvs <= MAX_SIMD_DEGREE_OR_2); // The following loop never executes when MAX_SIMD_DEGREE_OR_2 is 2, because // as we just asserted, num_cvs will always be <=2 in that case. But GCC // (particularly GCC 8.5) can't tell that it never executes, and if NDEBUG is // set then it emits incorrect warnings here. We tried a few different // hacks to silence these, but in the end our hacks just produced different // warnings (see https://github.com/BLAKE3-team/BLAKE3/pull/380). Out of // desperation, we ifdef out this entire loop when we know it's not needed. #if MAX_SIMD_DEGREE_OR_2 > 2 // If MAX_SIMD_DEGREE_OR_2 is greater than 2 and there's enough input, // compress_subtree_wide() returns more than 2 chaining values. Condense // them into 2 by forming parent nodes repeatedly. uint8_t out_array[MAX_SIMD_DEGREE_OR_2 * BLAKE3_OUT_LEN / 2]; while (num_cvs > 2) { num_cvs = compress_parents_parallel(cv_array, num_cvs, key, flags, out_array); memcpy(cv_array, out_array, num_cvs * BLAKE3_OUT_LEN); } #endif memcpy(out, cv_array, 2 * BLAKE3_OUT_LEN); } INLINE void hasher_init_base(blake3_hasher *self, const uint32_t key[8], uint8_t flags) { memcpy(self->key, key, BLAKE3_KEY_LEN); chunk_state_init(&self->chunk, key, flags); self->cv_stack_len = 0; } void blake3_hasher_init(blake3_hasher *self) { hasher_init_base(self, IV, 0); } void blake3_hasher_init_keyed(blake3_hasher *self, const uint8_t key[BLAKE3_KEY_LEN]) { uint32_t key_words[8]; load_key_words(key, key_words); hasher_init_base(self, key_words, KEYED_HASH); } void blake3_hasher_init_derive_key_raw(blake3_hasher *self, const void *context, size_t context_len) { blake3_hasher context_hasher; hasher_init_base(&context_hasher, IV, DERIVE_KEY_CONTEXT); blake3_hasher_update(&context_hasher, context, context_len); uint8_t context_key[BLAKE3_KEY_LEN]; blake3_hasher_finalize(&context_hasher, context_key, BLAKE3_KEY_LEN); uint32_t context_key_words[8]; load_key_words(context_key, context_key_words); hasher_init_base(self, context_key_words, DERIVE_KEY_MATERIAL); } void blake3_hasher_init_derive_key(blake3_hasher *self, const char *context) { blake3_hasher_init_derive_key_raw(self, context, strlen(context)); } // As described in hasher_push_cv() below, we do "lazy merging", delaying // merges until right before the next CV is about to be added. This is // different from the reference implementation. Another difference is that we // aren't always merging 1 chunk at a time. Instead, each CV might represent // any power-of-two number of chunks, as long as the smaller-above-larger stack // order is maintained. Instead of the "count the trailing 0-bits" algorithm // described in the spec, we use a "count the total number of 1-bits" variant // that doesn't require us to retain the subtree size of the CV on top of the // stack. The principle is the same: each CV that should remain in the stack is // represented by a 1-bit in the total number of chunks (or bytes) so far. INLINE void hasher_merge_cv_stack(blake3_hasher *self, uint64_t total_len) { size_t post_merge_stack_len = (size_t)popcnt(total_len); while (self->cv_stack_len > post_merge_stack_len) { uint8_t *parent_node = &self->cv_stack[(self->cv_stack_len - 2) * BLAKE3_OUT_LEN]; output_t output = parent_output(parent_node, self->key, self->chunk.flags); output_chaining_value(&output, parent_node); self->cv_stack_len -= 1; } } // In reference_impl.rs, we merge the new CV with existing CVs from the stack // before pushing it. We can do that because we know more input is coming, so // we know none of the merges are root. // // This setting is different. We want to feed as much input as possible to // compress_subtree_wide(), without setting aside anything for the chunk_state. // If the user gives us 64 KiB, we want to parallelize over all 64 KiB at once // as a single subtree, if at all possible. // // This leads to two problems: // 1) This 64 KiB input might be the only call that ever gets made to update. // In this case, the root node of the 64 KiB subtree would be the root node // of the whole tree, and it would need to be ROOT finalized. We can't // compress it until we know. // 2) This 64 KiB input might complete a larger tree, whose root node is // similarly going to be the root of the whole tree. For example, maybe // we have 196 KiB (that is, 128 + 64) hashed so far. We can't compress the // node at the root of the 256 KiB subtree until we know how to finalize it. // // The second problem is solved with "lazy merging". That is, when we're about // to add a CV to the stack, we don't merge it with anything first, as the // reference impl does. Instead we do merges using the *previous* CV that was // added, which is sitting on top of the stack, and we put the new CV // (unmerged) on top of the stack afterwards. This guarantees that we never // merge the root node until finalize(). // // Solving the first problem requires an additional tool, // compress_subtree_to_parent_node(). That function always returns the top // *two* chaining values of the subtree it's compressing. We then do lazy // merging with each of them separately, so that the second CV will always // remain unmerged. (That also helps us support extendable output when we're // hashing an input all-at-once.) INLINE void hasher_push_cv(blake3_hasher *self, uint8_t new_cv[BLAKE3_OUT_LEN], uint64_t chunk_counter) { hasher_merge_cv_stack(self, chunk_counter); memcpy(&self->cv_stack[self->cv_stack_len * BLAKE3_OUT_LEN], new_cv, BLAKE3_OUT_LEN); self->cv_stack_len += 1; } INLINE void blake3_hasher_update_base(blake3_hasher *self, const void *input, size_t input_len, bool use_tbb) { // Explicitly checking for zero avoids causing UB by passing a null pointer // to memcpy. This comes up in practice with things like: // std::vector v; // blake3_hasher_update(&hasher, v.data(), v.size()); if (input_len == 0) { return; } const uint8_t *input_bytes = (const uint8_t *)input; // If we have some partial chunk bytes in the internal chunk_state, we need // to finish that chunk first. if (chunk_state_len(&self->chunk) > 0) { size_t take = BLAKE3_CHUNK_LEN - chunk_state_len(&self->chunk); if (take > input_len) { take = input_len; } chunk_state_update(&self->chunk, input_bytes, take); input_bytes += take; input_len -= take; // If we've filled the current chunk and there's more coming, finalize this // chunk and proceed. In this case we know it's not the root. if (input_len > 0) { output_t output = chunk_state_output(&self->chunk); uint8_t chunk_cv[32]; output_chaining_value(&output, chunk_cv); hasher_push_cv(self, chunk_cv, self->chunk.chunk_counter); chunk_state_reset(&self->chunk, self->key, self->chunk.chunk_counter + 1); } else { return; } } // Now the chunk_state is clear, and we have more input. If there's more than // a single chunk (so, definitely not the root chunk), hash the largest whole // subtree we can, with the full benefits of SIMD (and maybe in the future, // multi-threading) parallelism. Two restrictions: // - The subtree has to be a power-of-2 number of chunks. Only subtrees along // the right edge can be incomplete, and we don't know where the right edge // is going to be until we get to finalize(). // - The subtree must evenly divide the total number of chunks up until this // point (if total is not 0). If the current incomplete subtree is only // waiting for 1 more chunk, we can't hash a subtree of 4 chunks. We have // to complete the current subtree first. // Because we might need to break up the input to form powers of 2, or to // evenly divide what we already have, this part runs in a loop. while (input_len > BLAKE3_CHUNK_LEN) { size_t subtree_len = round_down_to_power_of_2(input_len); uint64_t count_so_far = self->chunk.chunk_counter * BLAKE3_CHUNK_LEN; // Shrink the subtree_len until it evenly divides the count so far. We know // that subtree_len itself is a power of 2, so we can use a bitmasking // trick instead of an actual remainder operation. (Note that if the caller // consistently passes power-of-2 inputs of the same size, as is hopefully // typical, this loop condition will always fail, and subtree_len will // always be the full length of the input.) // // An aside: We don't have to shrink subtree_len quite this much. For // example, if count_so_far is 1, we could pass 2 chunks to // compress_subtree_to_parent_node. Since we'll get 2 CVs back, we'll still // get the right answer in the end, and we might get to use 2-way SIMD // parallelism. The problem with this optimization, is that it gets us // stuck always hashing 2 chunks. The total number of chunks will remain // odd, and we'll never graduate to higher degrees of parallelism. See // https://github.com/BLAKE3-team/BLAKE3/issues/69. while ((((uint64_t)(subtree_len - 1)) & count_so_far) != 0) { subtree_len /= 2; } // The shrunken subtree_len might now be 1 chunk long. If so, hash that one // chunk by itself. Otherwise, compress the subtree into a pair of CVs. uint64_t subtree_chunks = subtree_len / BLAKE3_CHUNK_LEN; if (subtree_len <= BLAKE3_CHUNK_LEN) { blake3_chunk_state chunk_state; chunk_state_init(&chunk_state, self->key, self->chunk.flags); chunk_state.chunk_counter = self->chunk.chunk_counter; chunk_state_update(&chunk_state, input_bytes, subtree_len); output_t output = chunk_state_output(&chunk_state); uint8_t cv[BLAKE3_OUT_LEN]; output_chaining_value(&output, cv); hasher_push_cv(self, cv, chunk_state.chunk_counter); } else { // This is the high-performance happy path, though getting here depends // on the caller giving us a long enough input. uint8_t cv_pair[2 * BLAKE3_OUT_LEN]; compress_subtree_to_parent_node(input_bytes, subtree_len, self->key, self->chunk.chunk_counter, self->chunk.flags, cv_pair, use_tbb); hasher_push_cv(self, cv_pair, self->chunk.chunk_counter); hasher_push_cv(self, &cv_pair[BLAKE3_OUT_LEN], self->chunk.chunk_counter + (subtree_chunks / 2)); } self->chunk.chunk_counter += subtree_chunks; input_bytes += subtree_len; input_len -= subtree_len; } // If there's any remaining input less than a full chunk, add it to the chunk // state. In that case, also do a final merge loop to make sure the subtree // stack doesn't contain any unmerged pairs. The remaining input means we // know these merges are non-root. This merge loop isn't strictly necessary // here, because hasher_push_chunk_cv already does its own merge loop, but it // simplifies blake3_hasher_finalize below. if (input_len > 0) { chunk_state_update(&self->chunk, input_bytes, input_len); hasher_merge_cv_stack(self, self->chunk.chunk_counter); } } void blake3_hasher_update(blake3_hasher *self, const void *input, size_t input_len) { bool use_tbb = false; blake3_hasher_update_base(self, input, input_len, use_tbb); } #if defined(BLAKE3_USE_TBB) void blake3_hasher_update_tbb(blake3_hasher *self, const void *input, size_t input_len) { bool use_tbb = true; blake3_hasher_update_base(self, input, input_len, use_tbb); } #endif // BLAKE3_USE_TBB void blake3_hasher_finalize(const blake3_hasher *self, uint8_t *out, size_t out_len) { blake3_hasher_finalize_seek(self, 0, out, out_len); } void blake3_hasher_finalize_seek(const blake3_hasher *self, uint64_t seek, uint8_t *out, size_t out_len) { // Explicitly checking for zero avoids causing UB by passing a null pointer // to memcpy. This comes up in practice with things like: // std::vector v; // blake3_hasher_finalize(&hasher, v.data(), v.size()); if (out_len == 0) { return; } // If the subtree stack is empty, then the current chunk is the root. if (self->cv_stack_len == 0) { output_t output = chunk_state_output(&self->chunk); output_root_bytes(&output, seek, out, out_len); return; } // If there are any bytes in the chunk state, finalize that chunk and do a // roll-up merge between that chunk hash and every subtree in the stack. In // this case, the extra merge loop at the end of blake3_hasher_update // guarantees that none of the subtrees in the stack need to be merged with // each other first. Otherwise, if there are no bytes in the chunk state, // then the top of the stack is a chunk hash, and we start the merge from // that. output_t output; size_t cvs_remaining; if (chunk_state_len(&self->chunk) > 0) { cvs_remaining = self->cv_stack_len; output = chunk_state_output(&self->chunk); } else { // There are always at least 2 CVs in the stack in this case. cvs_remaining = self->cv_stack_len - 2; output = parent_output(&self->cv_stack[cvs_remaining * 32], self->key, self->chunk.flags); } while (cvs_remaining > 0) { cvs_remaining -= 1; uint8_t parent_block[BLAKE3_BLOCK_LEN]; memcpy(parent_block, &self->cv_stack[cvs_remaining * 32], 32); output_chaining_value(&output, &parent_block[32]); output = parent_output(parent_block, self->key, self->chunk.flags); } output_root_bytes(&output, seek, out, out_len); } void blake3_hasher_reset(blake3_hasher *self) { chunk_state_reset(&self->chunk, self->key, 0); self->cv_stack_len = 0; } librecast/libs/blake3/c/blake3.h000066400000000000000000000055251502456746400167000ustar00rootroot00000000000000#ifndef BLAKE3_H #define BLAKE3_H #include #include #if !defined(BLAKE3_API) # if defined(_WIN32) || defined(__CYGWIN__) # if defined(BLAKE3_DLL) # if defined(BLAKE3_DLL_EXPORTS) # define BLAKE3_API __declspec(dllexport) # else # define BLAKE3_API __declspec(dllimport) # endif # define BLAKE3_PRIVATE # else # define BLAKE3_API # define BLAKE3_PRIVATE # endif # elif __GNUC__ >= 4 # define BLAKE3_API __attribute__((visibility("default"))) # define BLAKE3_PRIVATE __attribute__((visibility("hidden"))) # else # define BLAKE3_API # define BLAKE3_PRIVATE # endif #endif #ifdef __cplusplus extern "C" { #endif #define BLAKE3_VERSION_STRING "1.7.0" #define BLAKE3_KEY_LEN 32 #define BLAKE3_OUT_LEN 32 #define BLAKE3_BLOCK_LEN 64 #define BLAKE3_CHUNK_LEN 1024 #define BLAKE3_MAX_DEPTH 54 // This struct is a private implementation detail. It has to be here because // it's part of blake3_hasher below. typedef struct { uint32_t cv[8]; uint64_t chunk_counter; uint8_t buf[BLAKE3_BLOCK_LEN]; uint8_t buf_len; uint8_t blocks_compressed; uint8_t flags; } blake3_chunk_state; typedef struct { uint32_t key[8]; blake3_chunk_state chunk; uint8_t cv_stack_len; // The stack size is MAX_DEPTH + 1 because we do lazy merging. For example, // with 7 chunks, we have 3 entries in the stack. Adding an 8th chunk // requires a 4th entry, rather than merging everything down to 1, because we // don't know whether more input is coming. This is different from how the // reference implementation does things. uint8_t cv_stack[(BLAKE3_MAX_DEPTH + 1) * BLAKE3_OUT_LEN]; } blake3_hasher; BLAKE3_API const char *blake3_version(void); BLAKE3_API void blake3_hasher_init(blake3_hasher *self); BLAKE3_API void blake3_hasher_init_keyed(blake3_hasher *self, const uint8_t key[BLAKE3_KEY_LEN]); BLAKE3_API void blake3_hasher_init_derive_key(blake3_hasher *self, const char *context); BLAKE3_API void blake3_hasher_init_derive_key_raw(blake3_hasher *self, const void *context, size_t context_len); BLAKE3_API void blake3_hasher_update(blake3_hasher *self, const void *input, size_t input_len); #if defined(BLAKE3_USE_TBB) BLAKE3_API void blake3_hasher_update_tbb(blake3_hasher *self, const void *input, size_t input_len); #endif // BLAKE3_USE_TBB BLAKE3_API void blake3_hasher_finalize(const blake3_hasher *self, uint8_t *out, size_t out_len); BLAKE3_API void blake3_hasher_finalize_seek(const blake3_hasher *self, uint64_t seek, uint8_t *out, size_t out_len); BLAKE3_API void blake3_hasher_reset(blake3_hasher *self); #ifdef __cplusplus } #endif #endif /* BLAKE3_H */ librecast/libs/blake3/c/blake3_avx2.c000066400000000000000000000302441502456746400176270ustar00rootroot00000000000000#include "blake3_impl.h" #include #define DEGREE 8 INLINE __m256i loadu(const uint8_t src[32]) { return _mm256_loadu_si256((const __m256i *)src); } INLINE void storeu(__m256i src, uint8_t dest[16]) { _mm256_storeu_si256((__m256i *)dest, src); } INLINE __m256i addv(__m256i a, __m256i b) { return _mm256_add_epi32(a, b); } // Note that clang-format doesn't like the name "xor" for some reason. INLINE __m256i xorv(__m256i a, __m256i b) { return _mm256_xor_si256(a, b); } INLINE __m256i set1(uint32_t x) { return _mm256_set1_epi32((int32_t)x); } INLINE __m256i rot16(__m256i x) { return _mm256_shuffle_epi8( x, _mm256_set_epi8(13, 12, 15, 14, 9, 8, 11, 10, 5, 4, 7, 6, 1, 0, 3, 2, 13, 12, 15, 14, 9, 8, 11, 10, 5, 4, 7, 6, 1, 0, 3, 2)); } INLINE __m256i rot12(__m256i x) { return _mm256_or_si256(_mm256_srli_epi32(x, 12), _mm256_slli_epi32(x, 32 - 12)); } INLINE __m256i rot8(__m256i x) { return _mm256_shuffle_epi8( x, _mm256_set_epi8(12, 15, 14, 13, 8, 11, 10, 9, 4, 7, 6, 5, 0, 3, 2, 1, 12, 15, 14, 13, 8, 11, 10, 9, 4, 7, 6, 5, 0, 3, 2, 1)); } INLINE __m256i rot7(__m256i x) { return _mm256_or_si256(_mm256_srli_epi32(x, 7), _mm256_slli_epi32(x, 32 - 7)); } INLINE void round_fn(__m256i v[16], __m256i m[16], size_t r) { v[0] = addv(v[0], m[(size_t)MSG_SCHEDULE[r][0]]); v[1] = addv(v[1], m[(size_t)MSG_SCHEDULE[r][2]]); v[2] = addv(v[2], m[(size_t)MSG_SCHEDULE[r][4]]); v[3] = addv(v[3], m[(size_t)MSG_SCHEDULE[r][6]]); v[0] = addv(v[0], v[4]); v[1] = addv(v[1], v[5]); v[2] = addv(v[2], v[6]); v[3] = addv(v[3], v[7]); v[12] = xorv(v[12], v[0]); v[13] = xorv(v[13], v[1]); v[14] = xorv(v[14], v[2]); v[15] = xorv(v[15], v[3]); v[12] = rot16(v[12]); v[13] = rot16(v[13]); v[14] = rot16(v[14]); v[15] = rot16(v[15]); v[8] = addv(v[8], v[12]); v[9] = addv(v[9], v[13]); v[10] = addv(v[10], v[14]); v[11] = addv(v[11], v[15]); v[4] = xorv(v[4], v[8]); v[5] = xorv(v[5], v[9]); v[6] = xorv(v[6], v[10]); v[7] = xorv(v[7], v[11]); v[4] = rot12(v[4]); v[5] = rot12(v[5]); v[6] = rot12(v[6]); v[7] = rot12(v[7]); v[0] = addv(v[0], m[(size_t)MSG_SCHEDULE[r][1]]); v[1] = addv(v[1], m[(size_t)MSG_SCHEDULE[r][3]]); v[2] = addv(v[2], m[(size_t)MSG_SCHEDULE[r][5]]); v[3] = addv(v[3], m[(size_t)MSG_SCHEDULE[r][7]]); v[0] = addv(v[0], v[4]); v[1] = addv(v[1], v[5]); v[2] = addv(v[2], v[6]); v[3] = addv(v[3], v[7]); v[12] = xorv(v[12], v[0]); v[13] = xorv(v[13], v[1]); v[14] = xorv(v[14], v[2]); v[15] = xorv(v[15], v[3]); v[12] = rot8(v[12]); v[13] = rot8(v[13]); v[14] = rot8(v[14]); v[15] = rot8(v[15]); v[8] = addv(v[8], v[12]); v[9] = addv(v[9], v[13]); v[10] = addv(v[10], v[14]); v[11] = addv(v[11], v[15]); v[4] = xorv(v[4], v[8]); v[5] = xorv(v[5], v[9]); v[6] = xorv(v[6], v[10]); v[7] = xorv(v[7], v[11]); v[4] = rot7(v[4]); v[5] = rot7(v[5]); v[6] = rot7(v[6]); v[7] = rot7(v[7]); v[0] = addv(v[0], m[(size_t)MSG_SCHEDULE[r][8]]); v[1] = addv(v[1], m[(size_t)MSG_SCHEDULE[r][10]]); v[2] = addv(v[2], m[(size_t)MSG_SCHEDULE[r][12]]); v[3] = addv(v[3], m[(size_t)MSG_SCHEDULE[r][14]]); v[0] = addv(v[0], v[5]); v[1] = addv(v[1], v[6]); v[2] = addv(v[2], v[7]); v[3] = addv(v[3], v[4]); v[15] = xorv(v[15], v[0]); v[12] = xorv(v[12], v[1]); v[13] = xorv(v[13], v[2]); v[14] = xorv(v[14], v[3]); v[15] = rot16(v[15]); v[12] = rot16(v[12]); v[13] = rot16(v[13]); v[14] = rot16(v[14]); v[10] = addv(v[10], v[15]); v[11] = addv(v[11], v[12]); v[8] = addv(v[8], v[13]); v[9] = addv(v[9], v[14]); v[5] = xorv(v[5], v[10]); v[6] = xorv(v[6], v[11]); v[7] = xorv(v[7], v[8]); v[4] = xorv(v[4], v[9]); v[5] = rot12(v[5]); v[6] = rot12(v[6]); v[7] = rot12(v[7]); v[4] = rot12(v[4]); v[0] = addv(v[0], m[(size_t)MSG_SCHEDULE[r][9]]); v[1] = addv(v[1], m[(size_t)MSG_SCHEDULE[r][11]]); v[2] = addv(v[2], m[(size_t)MSG_SCHEDULE[r][13]]); v[3] = addv(v[3], m[(size_t)MSG_SCHEDULE[r][15]]); v[0] = addv(v[0], v[5]); v[1] = addv(v[1], v[6]); v[2] = addv(v[2], v[7]); v[3] = addv(v[3], v[4]); v[15] = xorv(v[15], v[0]); v[12] = xorv(v[12], v[1]); v[13] = xorv(v[13], v[2]); v[14] = xorv(v[14], v[3]); v[15] = rot8(v[15]); v[12] = rot8(v[12]); v[13] = rot8(v[13]); v[14] = rot8(v[14]); v[10] = addv(v[10], v[15]); v[11] = addv(v[11], v[12]); v[8] = addv(v[8], v[13]); v[9] = addv(v[9], v[14]); v[5] = xorv(v[5], v[10]); v[6] = xorv(v[6], v[11]); v[7] = xorv(v[7], v[8]); v[4] = xorv(v[4], v[9]); v[5] = rot7(v[5]); v[6] = rot7(v[6]); v[7] = rot7(v[7]); v[4] = rot7(v[4]); } INLINE void transpose_vecs(__m256i vecs[DEGREE]) { // Interleave 32-bit lanes. The low unpack is lanes 00/11/44/55, and the high // is 22/33/66/77. __m256i ab_0145 = _mm256_unpacklo_epi32(vecs[0], vecs[1]); __m256i ab_2367 = _mm256_unpackhi_epi32(vecs[0], vecs[1]); __m256i cd_0145 = _mm256_unpacklo_epi32(vecs[2], vecs[3]); __m256i cd_2367 = _mm256_unpackhi_epi32(vecs[2], vecs[3]); __m256i ef_0145 = _mm256_unpacklo_epi32(vecs[4], vecs[5]); __m256i ef_2367 = _mm256_unpackhi_epi32(vecs[4], vecs[5]); __m256i gh_0145 = _mm256_unpacklo_epi32(vecs[6], vecs[7]); __m256i gh_2367 = _mm256_unpackhi_epi32(vecs[6], vecs[7]); // Interleave 64-bit lanes. The low unpack is lanes 00/22 and the high is // 11/33. __m256i abcd_04 = _mm256_unpacklo_epi64(ab_0145, cd_0145); __m256i abcd_15 = _mm256_unpackhi_epi64(ab_0145, cd_0145); __m256i abcd_26 = _mm256_unpacklo_epi64(ab_2367, cd_2367); __m256i abcd_37 = _mm256_unpackhi_epi64(ab_2367, cd_2367); __m256i efgh_04 = _mm256_unpacklo_epi64(ef_0145, gh_0145); __m256i efgh_15 = _mm256_unpackhi_epi64(ef_0145, gh_0145); __m256i efgh_26 = _mm256_unpacklo_epi64(ef_2367, gh_2367); __m256i efgh_37 = _mm256_unpackhi_epi64(ef_2367, gh_2367); // Interleave 128-bit lanes. vecs[0] = _mm256_permute2x128_si256(abcd_04, efgh_04, 0x20); vecs[1] = _mm256_permute2x128_si256(abcd_15, efgh_15, 0x20); vecs[2] = _mm256_permute2x128_si256(abcd_26, efgh_26, 0x20); vecs[3] = _mm256_permute2x128_si256(abcd_37, efgh_37, 0x20); vecs[4] = _mm256_permute2x128_si256(abcd_04, efgh_04, 0x31); vecs[5] = _mm256_permute2x128_si256(abcd_15, efgh_15, 0x31); vecs[6] = _mm256_permute2x128_si256(abcd_26, efgh_26, 0x31); vecs[7] = _mm256_permute2x128_si256(abcd_37, efgh_37, 0x31); } INLINE void transpose_msg_vecs(const uint8_t *const *inputs, size_t block_offset, __m256i out[16]) { out[0] = loadu(&inputs[0][block_offset + 0 * sizeof(__m256i)]); out[1] = loadu(&inputs[1][block_offset + 0 * sizeof(__m256i)]); out[2] = loadu(&inputs[2][block_offset + 0 * sizeof(__m256i)]); out[3] = loadu(&inputs[3][block_offset + 0 * sizeof(__m256i)]); out[4] = loadu(&inputs[4][block_offset + 0 * sizeof(__m256i)]); out[5] = loadu(&inputs[5][block_offset + 0 * sizeof(__m256i)]); out[6] = loadu(&inputs[6][block_offset + 0 * sizeof(__m256i)]); out[7] = loadu(&inputs[7][block_offset + 0 * sizeof(__m256i)]); out[8] = loadu(&inputs[0][block_offset + 1 * sizeof(__m256i)]); out[9] = loadu(&inputs[1][block_offset + 1 * sizeof(__m256i)]); out[10] = loadu(&inputs[2][block_offset + 1 * sizeof(__m256i)]); out[11] = loadu(&inputs[3][block_offset + 1 * sizeof(__m256i)]); out[12] = loadu(&inputs[4][block_offset + 1 * sizeof(__m256i)]); out[13] = loadu(&inputs[5][block_offset + 1 * sizeof(__m256i)]); out[14] = loadu(&inputs[6][block_offset + 1 * sizeof(__m256i)]); out[15] = loadu(&inputs[7][block_offset + 1 * sizeof(__m256i)]); for (size_t i = 0; i < 8; ++i) { _mm_prefetch((const void *)&inputs[i][block_offset + 256], _MM_HINT_T0); } transpose_vecs(&out[0]); transpose_vecs(&out[8]); } INLINE void load_counters(uint64_t counter, bool increment_counter, __m256i *out_lo, __m256i *out_hi) { const __m256i mask = _mm256_set1_epi32(-(int32_t)increment_counter); const __m256i add0 = _mm256_set_epi32(7, 6, 5, 4, 3, 2, 1, 0); const __m256i add1 = _mm256_and_si256(mask, add0); __m256i l = _mm256_add_epi32(_mm256_set1_epi32((int32_t)counter), add1); __m256i carry = _mm256_cmpgt_epi32(_mm256_xor_si256(add1, _mm256_set1_epi32(0x80000000)), _mm256_xor_si256( l, _mm256_set1_epi32(0x80000000))); __m256i h = _mm256_sub_epi32(_mm256_set1_epi32((int32_t)(counter >> 32)), carry); *out_lo = l; *out_hi = h; } static void blake3_hash8_avx2(const uint8_t *const *inputs, size_t blocks, const uint32_t key[8], uint64_t counter, bool increment_counter, uint8_t flags, uint8_t flags_start, uint8_t flags_end, uint8_t *out) { __m256i h_vecs[8] = { set1(key[0]), set1(key[1]), set1(key[2]), set1(key[3]), set1(key[4]), set1(key[5]), set1(key[6]), set1(key[7]), }; __m256i counter_low_vec, counter_high_vec; load_counters(counter, increment_counter, &counter_low_vec, &counter_high_vec); uint8_t block_flags = flags | flags_start; for (size_t block = 0; block < blocks; block++) { if (block + 1 == blocks) { block_flags |= flags_end; } __m256i block_len_vec = set1(BLAKE3_BLOCK_LEN); __m256i block_flags_vec = set1(block_flags); __m256i msg_vecs[16]; transpose_msg_vecs(inputs, block * BLAKE3_BLOCK_LEN, msg_vecs); __m256i v[16] = { h_vecs[0], h_vecs[1], h_vecs[2], h_vecs[3], h_vecs[4], h_vecs[5], h_vecs[6], h_vecs[7], set1(IV[0]), set1(IV[1]), set1(IV[2]), set1(IV[3]), counter_low_vec, counter_high_vec, block_len_vec, block_flags_vec, }; round_fn(v, msg_vecs, 0); round_fn(v, msg_vecs, 1); round_fn(v, msg_vecs, 2); round_fn(v, msg_vecs, 3); round_fn(v, msg_vecs, 4); round_fn(v, msg_vecs, 5); round_fn(v, msg_vecs, 6); h_vecs[0] = xorv(v[0], v[8]); h_vecs[1] = xorv(v[1], v[9]); h_vecs[2] = xorv(v[2], v[10]); h_vecs[3] = xorv(v[3], v[11]); h_vecs[4] = xorv(v[4], v[12]); h_vecs[5] = xorv(v[5], v[13]); h_vecs[6] = xorv(v[6], v[14]); h_vecs[7] = xorv(v[7], v[15]); block_flags = flags; } transpose_vecs(h_vecs); storeu(h_vecs[0], &out[0 * sizeof(__m256i)]); storeu(h_vecs[1], &out[1 * sizeof(__m256i)]); storeu(h_vecs[2], &out[2 * sizeof(__m256i)]); storeu(h_vecs[3], &out[3 * sizeof(__m256i)]); storeu(h_vecs[4], &out[4 * sizeof(__m256i)]); storeu(h_vecs[5], &out[5 * sizeof(__m256i)]); storeu(h_vecs[6], &out[6 * sizeof(__m256i)]); storeu(h_vecs[7], &out[7 * sizeof(__m256i)]); } #if !defined(BLAKE3_NO_SSE41) void blake3_hash_many_sse41(const uint8_t *const *inputs, size_t num_inputs, size_t blocks, const uint32_t key[8], uint64_t counter, bool increment_counter, uint8_t flags, uint8_t flags_start, uint8_t flags_end, uint8_t *out); #else void blake3_hash_many_portable(const uint8_t *const *inputs, size_t num_inputs, size_t blocks, const uint32_t key[8], uint64_t counter, bool increment_counter, uint8_t flags, uint8_t flags_start, uint8_t flags_end, uint8_t *out); #endif void blake3_hash_many_avx2(const uint8_t *const *inputs, size_t num_inputs, size_t blocks, const uint32_t key[8], uint64_t counter, bool increment_counter, uint8_t flags, uint8_t flags_start, uint8_t flags_end, uint8_t *out) { while (num_inputs >= DEGREE) { blake3_hash8_avx2(inputs, blocks, key, counter, increment_counter, flags, flags_start, flags_end, out); if (increment_counter) { counter += DEGREE; } inputs += DEGREE; num_inputs -= DEGREE; out = &out[DEGREE * BLAKE3_OUT_LEN]; } #if !defined(BLAKE3_NO_SSE41) blake3_hash_many_sse41(inputs, num_inputs, blocks, key, counter, increment_counter, flags, flags_start, flags_end, out); #else blake3_hash_many_portable(inputs, num_inputs, blocks, key, counter, increment_counter, flags, flags_start, flags_end, out); #endif } librecast/libs/blake3/c/blake3_avx2_x86-64_unix.S000066400000000000000000002010021502456746400215760ustar00rootroot00000000000000#if defined(__ELF__) && defined(__linux__) .section .note.GNU-stack,"",%progbits #endif #if defined(__ELF__) && defined(__CET__) && defined(__has_include) #if __has_include() #include #endif #endif #if !defined(_CET_ENDBR) #define _CET_ENDBR #endif .intel_syntax noprefix .global _blake3_hash_many_avx2 .global blake3_hash_many_avx2 #ifdef __APPLE__ .text #else .section .text #endif .p2align 6 _blake3_hash_many_avx2: blake3_hash_many_avx2: _CET_ENDBR push r15 push r14 push r13 push r12 push rbx push rbp mov rbp, rsp sub rsp, 680 and rsp, 0xFFFFFFFFFFFFFFC0 neg r9d vmovd xmm0, r9d vpbroadcastd ymm0, xmm0 vmovdqa ymmword ptr [rsp+0x280], ymm0 vpand ymm1, ymm0, ymmword ptr [ADD0+rip] vpand ymm2, ymm0, ymmword ptr [ADD1+rip] vmovdqa ymmword ptr [rsp+0x220], ymm2 vmovd xmm2, r8d vpbroadcastd ymm2, xmm2 vpaddd ymm2, ymm2, ymm1 vmovdqa ymmword ptr [rsp+0x240], ymm2 vpxor ymm1, ymm1, ymmword ptr [CMP_MSB_MASK+rip] vpxor ymm2, ymm2, ymmword ptr [CMP_MSB_MASK+rip] vpcmpgtd ymm2, ymm1, ymm2 shr r8, 32 vmovd xmm3, r8d vpbroadcastd ymm3, xmm3 vpsubd ymm3, ymm3, ymm2 vmovdqa ymmword ptr [rsp+0x260], ymm3 shl rdx, 6 mov qword ptr [rsp+0x2A0], rdx cmp rsi, 8 jc 3f 2: vpbroadcastd ymm0, dword ptr [rcx] vpbroadcastd ymm1, dword ptr [rcx+0x4] vpbroadcastd ymm2, dword ptr [rcx+0x8] vpbroadcastd ymm3, dword ptr [rcx+0xC] vpbroadcastd ymm4, dword ptr [rcx+0x10] vpbroadcastd ymm5, dword ptr [rcx+0x14] vpbroadcastd ymm6, dword ptr [rcx+0x18] vpbroadcastd ymm7, dword ptr [rcx+0x1C] mov r8, qword ptr [rdi] mov r9, qword ptr [rdi+0x8] mov r10, qword ptr [rdi+0x10] mov r11, qword ptr [rdi+0x18] mov r12, qword ptr [rdi+0x20] mov r13, qword ptr [rdi+0x28] mov r14, qword ptr [rdi+0x30] mov r15, qword ptr [rdi+0x38] movzx eax, byte ptr [rbp+0x38] movzx ebx, byte ptr [rbp+0x40] or eax, ebx xor edx, edx .p2align 5 9: movzx ebx, byte ptr [rbp+0x48] or ebx, eax add rdx, 64 cmp rdx, qword ptr [rsp+0x2A0] cmove eax, ebx mov dword ptr [rsp+0x200], eax vmovups xmm8, xmmword ptr [r8+rdx-0x40] vinsertf128 ymm8, ymm8, xmmword ptr [r12+rdx-0x40], 0x01 vmovups xmm9, xmmword ptr [r9+rdx-0x40] vinsertf128 ymm9, ymm9, xmmword ptr [r13+rdx-0x40], 0x01 vunpcklpd ymm12, ymm8, ymm9 vunpckhpd ymm13, ymm8, ymm9 vmovups xmm10, xmmword ptr [r10+rdx-0x40] vinsertf128 ymm10, ymm10, xmmword ptr [r14+rdx-0x40], 0x01 vmovups xmm11, xmmword ptr [r11+rdx-0x40] vinsertf128 ymm11, ymm11, xmmword ptr [r15+rdx-0x40], 0x01 vunpcklpd ymm14, ymm10, ymm11 vunpckhpd ymm15, ymm10, ymm11 vshufps ymm8, ymm12, ymm14, 136 vmovaps ymmword ptr [rsp], ymm8 vshufps ymm9, ymm12, ymm14, 221 vmovaps ymmword ptr [rsp+0x20], ymm9 vshufps ymm10, ymm13, ymm15, 136 vmovaps ymmword ptr [rsp+0x40], ymm10 vshufps ymm11, ymm13, ymm15, 221 vmovaps ymmword ptr [rsp+0x60], ymm11 vmovups xmm8, xmmword ptr [r8+rdx-0x30] vinsertf128 ymm8, ymm8, xmmword ptr [r12+rdx-0x30], 0x01 vmovups xmm9, xmmword ptr [r9+rdx-0x30] vinsertf128 ymm9, ymm9, xmmword ptr [r13+rdx-0x30], 0x01 vunpcklpd ymm12, ymm8, ymm9 vunpckhpd ymm13, ymm8, ymm9 vmovups xmm10, xmmword ptr [r10+rdx-0x30] vinsertf128 ymm10, ymm10, xmmword ptr [r14+rdx-0x30], 0x01 vmovups xmm11, xmmword ptr [r11+rdx-0x30] vinsertf128 ymm11, ymm11, xmmword ptr [r15+rdx-0x30], 0x01 vunpcklpd ymm14, ymm10, ymm11 vunpckhpd ymm15, ymm10, ymm11 vshufps ymm8, ymm12, ymm14, 136 vmovaps ymmword ptr [rsp+0x80], ymm8 vshufps ymm9, ymm12, ymm14, 221 vmovaps ymmword ptr [rsp+0xA0], ymm9 vshufps ymm10, ymm13, ymm15, 136 vmovaps ymmword ptr [rsp+0xC0], ymm10 vshufps ymm11, ymm13, ymm15, 221 vmovaps ymmword ptr [rsp+0xE0], ymm11 vmovups xmm8, xmmword ptr [r8+rdx-0x20] vinsertf128 ymm8, ymm8, xmmword ptr [r12+rdx-0x20], 0x01 vmovups xmm9, xmmword ptr [r9+rdx-0x20] vinsertf128 ymm9, ymm9, xmmword ptr [r13+rdx-0x20], 0x01 vunpcklpd ymm12, ymm8, ymm9 vunpckhpd ymm13, ymm8, ymm9 vmovups xmm10, xmmword ptr [r10+rdx-0x20] vinsertf128 ymm10, ymm10, xmmword ptr [r14+rdx-0x20], 0x01 vmovups xmm11, xmmword ptr [r11+rdx-0x20] vinsertf128 ymm11, ymm11, xmmword ptr [r15+rdx-0x20], 0x01 vunpcklpd ymm14, ymm10, ymm11 vunpckhpd ymm15, ymm10, ymm11 vshufps ymm8, ymm12, ymm14, 136 vmovaps ymmword ptr [rsp+0x100], ymm8 vshufps ymm9, ymm12, ymm14, 221 vmovaps ymmword ptr [rsp+0x120], ymm9 vshufps ymm10, ymm13, ymm15, 136 vmovaps ymmword ptr [rsp+0x140], ymm10 vshufps ymm11, ymm13, ymm15, 221 vmovaps ymmword ptr [rsp+0x160], ymm11 vmovups xmm8, xmmword ptr [r8+rdx-0x10] vinsertf128 ymm8, ymm8, xmmword ptr [r12+rdx-0x10], 0x01 vmovups xmm9, xmmword ptr [r9+rdx-0x10] vinsertf128 ymm9, ymm9, xmmword ptr [r13+rdx-0x10], 0x01 vunpcklpd ymm12, ymm8, ymm9 vunpckhpd ymm13, ymm8, ymm9 vmovups xmm10, xmmword ptr [r10+rdx-0x10] vinsertf128 ymm10, ymm10, xmmword ptr [r14+rdx-0x10], 0x01 vmovups xmm11, xmmword ptr [r11+rdx-0x10] vinsertf128 ymm11, ymm11, xmmword ptr [r15+rdx-0x10], 0x01 vunpcklpd ymm14, ymm10, ymm11 vunpckhpd ymm15, ymm10, ymm11 vshufps ymm8, ymm12, ymm14, 136 vmovaps ymmword ptr [rsp+0x180], ymm8 vshufps ymm9, ymm12, ymm14, 221 vmovaps ymmword ptr [rsp+0x1A0], ymm9 vshufps ymm10, ymm13, ymm15, 136 vmovaps ymmword ptr [rsp+0x1C0], ymm10 vshufps ymm11, ymm13, ymm15, 221 vmovaps ymmword ptr [rsp+0x1E0], ymm11 vpbroadcastd ymm15, dword ptr [rsp+0x200] prefetcht0 [r8+rdx+0x80] prefetcht0 [r12+rdx+0x80] prefetcht0 [r9+rdx+0x80] prefetcht0 [r13+rdx+0x80] prefetcht0 [r10+rdx+0x80] prefetcht0 [r14+rdx+0x80] prefetcht0 [r11+rdx+0x80] prefetcht0 [r15+rdx+0x80] vpaddd ymm0, ymm0, ymmword ptr [rsp] vpaddd ymm1, ymm1, ymmword ptr [rsp+0x40] vpaddd ymm2, ymm2, ymmword ptr [rsp+0x80] vpaddd ymm3, ymm3, ymmword ptr [rsp+0xC0] vpaddd ymm0, ymm0, ymm4 vpaddd ymm1, ymm1, ymm5 vpaddd ymm2, ymm2, ymm6 vpaddd ymm3, ymm3, ymm7 vpxor ymm12, ymm0, ymmword ptr [rsp+0x240] vpxor ymm13, ymm1, ymmword ptr [rsp+0x260] vpxor ymm14, ymm2, ymmword ptr [BLAKE3_BLOCK_LEN+rip] vpxor ymm15, ymm3, ymm15 vbroadcasti128 ymm8, xmmword ptr [ROT16+rip] vpshufb ymm12, ymm12, ymm8 vpshufb ymm13, ymm13, ymm8 vpshufb ymm14, ymm14, ymm8 vpshufb ymm15, ymm15, ymm8 vpaddd ymm8, ymm12, ymmword ptr [BLAKE3_IV_0+rip] vpaddd ymm9, ymm13, ymmword ptr [BLAKE3_IV_1+rip] vpaddd ymm10, ymm14, ymmword ptr [BLAKE3_IV_2+rip] vpaddd ymm11, ymm15, ymmword ptr [BLAKE3_IV_3+rip] vpxor ymm4, ymm4, ymm8 vpxor ymm5, ymm5, ymm9 vpxor ymm6, ymm6, ymm10 vpxor ymm7, ymm7, ymm11 vmovdqa ymmword ptr [rsp+0x200], ymm8 vpsrld ymm8, ymm4, 12 vpslld ymm4, ymm4, 20 vpor ymm4, ymm4, ymm8 vpsrld ymm8, ymm5, 12 vpslld ymm5, ymm5, 20 vpor ymm5, ymm5, ymm8 vpsrld ymm8, ymm6, 12 vpslld ymm6, ymm6, 20 vpor ymm6, ymm6, ymm8 vpsrld ymm8, ymm7, 12 vpslld ymm7, ymm7, 20 vpor ymm7, ymm7, ymm8 vpaddd ymm0, ymm0, ymmword ptr [rsp+0x20] vpaddd ymm1, ymm1, ymmword ptr [rsp+0x60] vpaddd ymm2, ymm2, ymmword ptr [rsp+0xA0] vpaddd ymm3, ymm3, ymmword ptr [rsp+0xE0] vpaddd ymm0, ymm0, ymm4 vpaddd ymm1, ymm1, ymm5 vpaddd ymm2, ymm2, ymm6 vpaddd ymm3, ymm3, ymm7 vpxor ymm12, ymm12, ymm0 vpxor ymm13, ymm13, ymm1 vpxor ymm14, ymm14, ymm2 vpxor ymm15, ymm15, ymm3 vbroadcasti128 ymm8, xmmword ptr [ROT8+rip] vpshufb ymm12, ymm12, ymm8 vpshufb ymm13, ymm13, ymm8 vpshufb ymm14, ymm14, ymm8 vpshufb ymm15, ymm15, ymm8 vpaddd ymm8, ymm12, ymmword ptr [rsp+0x200] vpaddd ymm9, ymm9, ymm13 vpaddd ymm10, ymm10, ymm14 vpaddd ymm11, ymm11, ymm15 vpxor ymm4, ymm4, ymm8 vpxor ymm5, ymm5, ymm9 vpxor ymm6, ymm6, ymm10 vpxor ymm7, ymm7, ymm11 vmovdqa ymmword ptr [rsp+0x200], ymm8 vpsrld ymm8, ymm4, 7 vpslld ymm4, ymm4, 25 vpor ymm4, ymm4, ymm8 vpsrld ymm8, ymm5, 7 vpslld ymm5, ymm5, 25 vpor ymm5, ymm5, ymm8 vpsrld ymm8, ymm6, 7 vpslld ymm6, ymm6, 25 vpor ymm6, ymm6, ymm8 vpsrld ymm8, ymm7, 7 vpslld ymm7, ymm7, 25 vpor ymm7, ymm7, ymm8 vpaddd ymm0, ymm0, ymmword ptr [rsp+0x100] vpaddd ymm1, ymm1, ymmword ptr [rsp+0x140] vpaddd ymm2, ymm2, ymmword ptr [rsp+0x180] vpaddd ymm3, ymm3, ymmword ptr [rsp+0x1C0] vpaddd ymm0, ymm0, ymm5 vpaddd ymm1, ymm1, ymm6 vpaddd ymm2, ymm2, ymm7 vpaddd ymm3, ymm3, ymm4 vpxor ymm15, ymm15, ymm0 vpxor ymm12, ymm12, ymm1 vpxor ymm13, ymm13, ymm2 vpxor ymm14, ymm14, ymm3 vbroadcasti128 ymm8, xmmword ptr [ROT16+rip] vpshufb ymm15, ymm15, ymm8 vpshufb ymm12, ymm12, ymm8 vpshufb ymm13, ymm13, ymm8 vpshufb ymm14, ymm14, ymm8 vpaddd ymm10, ymm10, ymm15 vpaddd ymm11, ymm11, ymm12 vpaddd ymm8, ymm13, ymmword ptr [rsp+0x200] vpaddd ymm9, ymm9, ymm14 vpxor ymm5, ymm5, ymm10 vpxor ymm6, ymm6, ymm11 vpxor ymm7, ymm7, ymm8 vpxor ymm4, ymm4, ymm9 vmovdqa ymmword ptr [rsp+0x200], ymm8 vpsrld ymm8, ymm5, 12 vpslld ymm5, ymm5, 20 vpor ymm5, ymm5, ymm8 vpsrld ymm8, ymm6, 12 vpslld ymm6, ymm6, 20 vpor ymm6, ymm6, ymm8 vpsrld ymm8, ymm7, 12 vpslld ymm7, ymm7, 20 vpor ymm7, ymm7, ymm8 vpsrld ymm8, ymm4, 12 vpslld ymm4, ymm4, 20 vpor ymm4, ymm4, ymm8 vpaddd ymm0, ymm0, ymmword ptr [rsp+0x120] vpaddd ymm1, ymm1, ymmword ptr [rsp+0x160] vpaddd ymm2, ymm2, ymmword ptr [rsp+0x1A0] vpaddd ymm3, ymm3, ymmword ptr [rsp+0x1E0] vpaddd ymm0, ymm0, ymm5 vpaddd ymm1, ymm1, ymm6 vpaddd ymm2, ymm2, ymm7 vpaddd ymm3, ymm3, ymm4 vpxor ymm15, ymm15, ymm0 vpxor ymm12, ymm12, ymm1 vpxor ymm13, ymm13, ymm2 vpxor ymm14, ymm14, ymm3 vbroadcasti128 ymm8, xmmword ptr [ROT8+rip] vpshufb ymm15, ymm15, ymm8 vpshufb ymm12, ymm12, ymm8 vpshufb ymm13, ymm13, ymm8 vpshufb ymm14, ymm14, ymm8 vpaddd ymm10, ymm10, ymm15 vpaddd ymm11, ymm11, ymm12 vpaddd ymm8, ymm13, ymmword ptr [rsp+0x200] vpaddd ymm9, ymm9, ymm14 vpxor ymm5, ymm5, ymm10 vpxor ymm6, ymm6, ymm11 vpxor ymm7, ymm7, ymm8 vpxor ymm4, ymm4, ymm9 vmovdqa ymmword ptr [rsp+0x200], ymm8 vpsrld ymm8, ymm5, 7 vpslld ymm5, ymm5, 25 vpor ymm5, ymm5, ymm8 vpsrld ymm8, ymm6, 7 vpslld ymm6, ymm6, 25 vpor ymm6, ymm6, ymm8 vpsrld ymm8, ymm7, 7 vpslld ymm7, ymm7, 25 vpor ymm7, ymm7, ymm8 vpsrld ymm8, ymm4, 7 vpslld ymm4, ymm4, 25 vpor ymm4, ymm4, ymm8 vpaddd ymm0, ymm0, ymmword ptr [rsp+0x40] vpaddd ymm1, ymm1, ymmword ptr [rsp+0x60] vpaddd ymm2, ymm2, ymmword ptr [rsp+0xE0] vpaddd ymm3, ymm3, ymmword ptr [rsp+0x80] vpaddd ymm0, ymm0, ymm4 vpaddd ymm1, ymm1, ymm5 vpaddd ymm2, ymm2, ymm6 vpaddd ymm3, ymm3, ymm7 vpxor ymm12, ymm12, ymm0 vpxor ymm13, ymm13, ymm1 vpxor ymm14, ymm14, ymm2 vpxor ymm15, ymm15, ymm3 vbroadcasti128 ymm8, xmmword ptr [ROT16+rip] vpshufb ymm12, ymm12, ymm8 vpshufb ymm13, ymm13, ymm8 vpshufb ymm14, ymm14, ymm8 vpshufb ymm15, ymm15, ymm8 vpaddd ymm8, ymm12, ymmword ptr [rsp+0x200] vpaddd ymm9, ymm9, ymm13 vpaddd ymm10, ymm10, ymm14 vpaddd ymm11, ymm11, ymm15 vpxor ymm4, ymm4, ymm8 vpxor ymm5, ymm5, ymm9 vpxor ymm6, ymm6, ymm10 vpxor ymm7, ymm7, ymm11 vmovdqa ymmword ptr [rsp+0x200], ymm8 vpsrld ymm8, ymm4, 12 vpslld ymm4, ymm4, 20 vpor ymm4, ymm4, ymm8 vpsrld ymm8, ymm5, 12 vpslld ymm5, ymm5, 20 vpor ymm5, ymm5, ymm8 vpsrld ymm8, ymm6, 12 vpslld ymm6, ymm6, 20 vpor ymm6, ymm6, ymm8 vpsrld ymm8, ymm7, 12 vpslld ymm7, ymm7, 20 vpor ymm7, ymm7, ymm8 vpaddd ymm0, ymm0, ymmword ptr [rsp+0xC0] vpaddd ymm1, ymm1, ymmword ptr [rsp+0x140] vpaddd ymm2, ymm2, ymmword ptr [rsp] vpaddd ymm3, ymm3, ymmword ptr [rsp+0x1A0] vpaddd ymm0, ymm0, ymm4 vpaddd ymm1, ymm1, ymm5 vpaddd ymm2, ymm2, ymm6 vpaddd ymm3, ymm3, ymm7 vpxor ymm12, ymm12, ymm0 vpxor ymm13, ymm13, ymm1 vpxor ymm14, ymm14, ymm2 vpxor ymm15, ymm15, ymm3 vbroadcasti128 ymm8, xmmword ptr [ROT8+rip] vpshufb ymm12, ymm12, ymm8 vpshufb ymm13, ymm13, ymm8 vpshufb ymm14, ymm14, ymm8 vpshufb ymm15, ymm15, ymm8 vpaddd ymm8, ymm12, ymmword ptr [rsp+0x200] vpaddd ymm9, ymm9, ymm13 vpaddd ymm10, ymm10, ymm14 vpaddd ymm11, ymm11, ymm15 vpxor ymm4, ymm4, ymm8 vpxor ymm5, ymm5, ymm9 vpxor ymm6, ymm6, ymm10 vpxor ymm7, ymm7, ymm11 vmovdqa ymmword ptr [rsp+0x200], ymm8 vpsrld ymm8, ymm4, 7 vpslld ymm4, ymm4, 25 vpor ymm4, ymm4, ymm8 vpsrld ymm8, ymm5, 7 vpslld ymm5, ymm5, 25 vpor ymm5, ymm5, ymm8 vpsrld ymm8, ymm6, 7 vpslld ymm6, ymm6, 25 vpor ymm6, ymm6, ymm8 vpsrld ymm8, ymm7, 7 vpslld ymm7, ymm7, 25 vpor ymm7, ymm7, ymm8 vpaddd ymm0, ymm0, ymmword ptr [rsp+0x20] vpaddd ymm1, ymm1, ymmword ptr [rsp+0x180] vpaddd ymm2, ymm2, ymmword ptr [rsp+0x120] vpaddd ymm3, ymm3, ymmword ptr [rsp+0x1E0] vpaddd ymm0, ymm0, ymm5 vpaddd ymm1, ymm1, ymm6 vpaddd ymm2, ymm2, ymm7 vpaddd ymm3, ymm3, ymm4 vpxor ymm15, ymm15, ymm0 vpxor ymm12, ymm12, ymm1 vpxor ymm13, ymm13, ymm2 vpxor ymm14, ymm14, ymm3 vbroadcasti128 ymm8, xmmword ptr [ROT16+rip] vpshufb ymm15, ymm15, ymm8 vpshufb ymm12, ymm12, ymm8 vpshufb ymm13, ymm13, ymm8 vpshufb ymm14, ymm14, ymm8 vpaddd ymm10, ymm10, ymm15 vpaddd ymm11, ymm11, ymm12 vpaddd ymm8, ymm13, ymmword ptr [rsp+0x200] vpaddd ymm9, ymm9, ymm14 vpxor ymm5, ymm5, ymm10 vpxor ymm6, ymm6, ymm11 vpxor ymm7, ymm7, ymm8 vpxor ymm4, ymm4, ymm9 vmovdqa ymmword ptr [rsp+0x200], ymm8 vpsrld ymm8, ymm5, 12 vpslld ymm5, ymm5, 20 vpor ymm5, ymm5, ymm8 vpsrld ymm8, ymm6, 12 vpslld ymm6, ymm6, 20 vpor ymm6, ymm6, ymm8 vpsrld ymm8, ymm7, 12 vpslld ymm7, ymm7, 20 vpor ymm7, ymm7, ymm8 vpsrld ymm8, ymm4, 12 vpslld ymm4, ymm4, 20 vpor ymm4, ymm4, ymm8 vpaddd ymm0, ymm0, ymmword ptr [rsp+0x160] vpaddd ymm1, ymm1, ymmword ptr [rsp+0xA0] vpaddd ymm2, ymm2, ymmword ptr [rsp+0x1C0] vpaddd ymm3, ymm3, ymmword ptr [rsp+0x100] vpaddd ymm0, ymm0, ymm5 vpaddd ymm1, ymm1, ymm6 vpaddd ymm2, ymm2, ymm7 vpaddd ymm3, ymm3, ymm4 vpxor ymm15, ymm15, ymm0 vpxor ymm12, ymm12, ymm1 vpxor ymm13, ymm13, ymm2 vpxor ymm14, ymm14, ymm3 vbroadcasti128 ymm8, xmmword ptr [ROT8+rip] vpshufb ymm15, ymm15, ymm8 vpshufb ymm12, ymm12, ymm8 vpshufb ymm13, ymm13, ymm8 vpshufb ymm14, ymm14, ymm8 vpaddd ymm10, ymm10, ymm15 vpaddd ymm11, ymm11, ymm12 vpaddd ymm8, ymm13, ymmword ptr [rsp+0x200] vpaddd ymm9, ymm9, ymm14 vpxor ymm5, ymm5, ymm10 vpxor ymm6, ymm6, ymm11 vpxor ymm7, ymm7, ymm8 vpxor ymm4, ymm4, ymm9 vmovdqa ymmword ptr [rsp+0x200], ymm8 vpsrld ymm8, ymm5, 7 vpslld ymm5, ymm5, 25 vpor ymm5, ymm5, ymm8 vpsrld ymm8, ymm6, 7 vpslld ymm6, ymm6, 25 vpor ymm6, ymm6, ymm8 vpsrld ymm8, ymm7, 7 vpslld ymm7, ymm7, 25 vpor ymm7, ymm7, ymm8 vpsrld ymm8, ymm4, 7 vpslld ymm4, ymm4, 25 vpor ymm4, ymm4, ymm8 vpaddd ymm0, ymm0, ymmword ptr [rsp+0x60] vpaddd ymm1, ymm1, ymmword ptr [rsp+0x140] vpaddd ymm2, ymm2, ymmword ptr [rsp+0x1A0] vpaddd ymm3, ymm3, ymmword ptr [rsp+0xE0] vpaddd ymm0, ymm0, ymm4 vpaddd ymm1, ymm1, ymm5 vpaddd ymm2, ymm2, ymm6 vpaddd ymm3, ymm3, ymm7 vpxor ymm12, ymm12, ymm0 vpxor ymm13, ymm13, ymm1 vpxor ymm14, ymm14, ymm2 vpxor ymm15, ymm15, ymm3 vbroadcasti128 ymm8, xmmword ptr [ROT16+rip] vpshufb ymm12, ymm12, ymm8 vpshufb ymm13, ymm13, ymm8 vpshufb ymm14, ymm14, ymm8 vpshufb ymm15, ymm15, ymm8 vpaddd ymm8, ymm12, ymmword ptr [rsp+0x200] vpaddd ymm9, ymm9, ymm13 vpaddd ymm10, ymm10, ymm14 vpaddd ymm11, ymm11, ymm15 vpxor ymm4, ymm4, ymm8 vpxor ymm5, ymm5, ymm9 vpxor ymm6, ymm6, ymm10 vpxor ymm7, ymm7, ymm11 vmovdqa ymmword ptr [rsp+0x200], ymm8 vpsrld ymm8, ymm4, 12 vpslld ymm4, ymm4, 20 vpor ymm4, ymm4, ymm8 vpsrld ymm8, ymm5, 12 vpslld ymm5, ymm5, 20 vpor ymm5, ymm5, ymm8 vpsrld ymm8, ymm6, 12 vpslld ymm6, ymm6, 20 vpor ymm6, ymm6, ymm8 vpsrld ymm8, ymm7, 12 vpslld ymm7, ymm7, 20 vpor ymm7, ymm7, ymm8 vpaddd ymm0, ymm0, ymmword ptr [rsp+0x80] vpaddd ymm1, ymm1, ymmword ptr [rsp+0x180] vpaddd ymm2, ymm2, ymmword ptr [rsp+0x40] vpaddd ymm3, ymm3, ymmword ptr [rsp+0x1C0] vpaddd ymm0, ymm0, ymm4 vpaddd ymm1, ymm1, ymm5 vpaddd ymm2, ymm2, ymm6 vpaddd ymm3, ymm3, ymm7 vpxor ymm12, ymm12, ymm0 vpxor ymm13, ymm13, ymm1 vpxor ymm14, ymm14, ymm2 vpxor ymm15, ymm15, ymm3 vbroadcasti128 ymm8, xmmword ptr [ROT8+rip] vpshufb ymm12, ymm12, ymm8 vpshufb ymm13, ymm13, ymm8 vpshufb ymm14, ymm14, ymm8 vpshufb ymm15, ymm15, ymm8 vpaddd ymm8, ymm12, ymmword ptr [rsp+0x200] vpaddd ymm9, ymm9, ymm13 vpaddd ymm10, ymm10, ymm14 vpaddd ymm11, ymm11, ymm15 vpxor ymm4, ymm4, ymm8 vpxor ymm5, ymm5, ymm9 vpxor ymm6, ymm6, ymm10 vpxor ymm7, ymm7, ymm11 vmovdqa ymmword ptr [rsp+0x200], ymm8 vpsrld ymm8, ymm4, 7 vpslld ymm4, ymm4, 25 vpor ymm4, ymm4, ymm8 vpsrld ymm8, ymm5, 7 vpslld ymm5, ymm5, 25 vpor ymm5, ymm5, ymm8 vpsrld ymm8, ymm6, 7 vpslld ymm6, ymm6, 25 vpor ymm6, ymm6, ymm8 vpsrld ymm8, ymm7, 7 vpslld ymm7, ymm7, 25 vpor ymm7, ymm7, ymm8 vpaddd ymm0, ymm0, ymmword ptr [rsp+0xC0] vpaddd ymm1, ymm1, ymmword ptr [rsp+0x120] vpaddd ymm2, ymm2, ymmword ptr [rsp+0x160] vpaddd ymm3, ymm3, ymmword ptr [rsp+0x100] vpaddd ymm0, ymm0, ymm5 vpaddd ymm1, ymm1, ymm6 vpaddd ymm2, ymm2, ymm7 vpaddd ymm3, ymm3, ymm4 vpxor ymm15, ymm15, ymm0 vpxor ymm12, ymm12, ymm1 vpxor ymm13, ymm13, ymm2 vpxor ymm14, ymm14, ymm3 vbroadcasti128 ymm8, xmmword ptr [ROT16+rip] vpshufb ymm15, ymm15, ymm8 vpshufb ymm12, ymm12, ymm8 vpshufb ymm13, ymm13, ymm8 vpshufb ymm14, ymm14, ymm8 vpaddd ymm10, ymm10, ymm15 vpaddd ymm11, ymm11, ymm12 vpaddd ymm8, ymm13, ymmword ptr [rsp+0x200] vpaddd ymm9, ymm9, ymm14 vpxor ymm5, ymm5, ymm10 vpxor ymm6, ymm6, ymm11 vpxor ymm7, ymm7, ymm8 vpxor ymm4, ymm4, ymm9 vmovdqa ymmword ptr [rsp+0x200], ymm8 vpsrld ymm8, ymm5, 12 vpslld ymm5, ymm5, 20 vpor ymm5, ymm5, ymm8 vpsrld ymm8, ymm6, 12 vpslld ymm6, ymm6, 20 vpor ymm6, ymm6, ymm8 vpsrld ymm8, ymm7, 12 vpslld ymm7, ymm7, 20 vpor ymm7, ymm7, ymm8 vpsrld ymm8, ymm4, 12 vpslld ymm4, ymm4, 20 vpor ymm4, ymm4, ymm8 vpaddd ymm0, ymm0, ymmword ptr [rsp+0xA0] vpaddd ymm1, ymm1, ymmword ptr [rsp] vpaddd ymm2, ymm2, ymmword ptr [rsp+0x1E0] vpaddd ymm3, ymm3, ymmword ptr [rsp+0x20] vpaddd ymm0, ymm0, ymm5 vpaddd ymm1, ymm1, ymm6 vpaddd ymm2, ymm2, ymm7 vpaddd ymm3, ymm3, ymm4 vpxor ymm15, ymm15, ymm0 vpxor ymm12, ymm12, ymm1 vpxor ymm13, ymm13, ymm2 vpxor ymm14, ymm14, ymm3 vbroadcasti128 ymm8, xmmword ptr [ROT8+rip] vpshufb ymm15, ymm15, ymm8 vpshufb ymm12, ymm12, ymm8 vpshufb ymm13, ymm13, ymm8 vpshufb ymm14, ymm14, ymm8 vpaddd ymm10, ymm10, ymm15 vpaddd ymm11, ymm11, ymm12 vpaddd ymm8, ymm13, ymmword ptr [rsp+0x200] vpaddd ymm9, ymm9, ymm14 vpxor ymm5, ymm5, ymm10 vpxor ymm6, ymm6, ymm11 vpxor ymm7, ymm7, ymm8 vpxor ymm4, ymm4, ymm9 vmovdqa ymmword ptr [rsp+0x200], ymm8 vpsrld ymm8, ymm5, 7 vpslld ymm5, ymm5, 25 vpor ymm5, ymm5, ymm8 vpsrld ymm8, ymm6, 7 vpslld ymm6, ymm6, 25 vpor ymm6, ymm6, ymm8 vpsrld ymm8, ymm7, 7 vpslld ymm7, ymm7, 25 vpor ymm7, ymm7, ymm8 vpsrld ymm8, ymm4, 7 vpslld ymm4, ymm4, 25 vpor ymm4, ymm4, ymm8 vpaddd ymm0, ymm0, ymmword ptr [rsp+0x140] vpaddd ymm1, ymm1, ymmword ptr [rsp+0x180] vpaddd ymm2, ymm2, ymmword ptr [rsp+0x1C0] vpaddd ymm3, ymm3, ymmword ptr [rsp+0x1A0] vpaddd ymm0, ymm0, ymm4 vpaddd ymm1, ymm1, ymm5 vpaddd ymm2, ymm2, ymm6 vpaddd ymm3, ymm3, ymm7 vpxor ymm12, ymm12, ymm0 vpxor ymm13, ymm13, ymm1 vpxor ymm14, ymm14, ymm2 vpxor ymm15, ymm15, ymm3 vbroadcasti128 ymm8, xmmword ptr [ROT16+rip] vpshufb ymm12, ymm12, ymm8 vpshufb ymm13, ymm13, ymm8 vpshufb ymm14, ymm14, ymm8 vpshufb ymm15, ymm15, ymm8 vpaddd ymm8, ymm12, ymmword ptr [rsp+0x200] vpaddd ymm9, ymm9, ymm13 vpaddd ymm10, ymm10, ymm14 vpaddd ymm11, ymm11, ymm15 vpxor ymm4, ymm4, ymm8 vpxor ymm5, ymm5, ymm9 vpxor ymm6, ymm6, ymm10 vpxor ymm7, ymm7, ymm11 vmovdqa ymmword ptr [rsp+0x200], ymm8 vpsrld ymm8, ymm4, 12 vpslld ymm4, ymm4, 20 vpor ymm4, ymm4, ymm8 vpsrld ymm8, ymm5, 12 vpslld ymm5, ymm5, 20 vpor ymm5, ymm5, ymm8 vpsrld ymm8, ymm6, 12 vpslld ymm6, ymm6, 20 vpor ymm6, ymm6, ymm8 vpsrld ymm8, ymm7, 12 vpslld ymm7, ymm7, 20 vpor ymm7, ymm7, ymm8 vpaddd ymm0, ymm0, ymmword ptr [rsp+0xE0] vpaddd ymm1, ymm1, ymmword ptr [rsp+0x120] vpaddd ymm2, ymm2, ymmword ptr [rsp+0x60] vpaddd ymm3, ymm3, ymmword ptr [rsp+0x1E0] vpaddd ymm0, ymm0, ymm4 vpaddd ymm1, ymm1, ymm5 vpaddd ymm2, ymm2, ymm6 vpaddd ymm3, ymm3, ymm7 vpxor ymm12, ymm12, ymm0 vpxor ymm13, ymm13, ymm1 vpxor ymm14, ymm14, ymm2 vpxor ymm15, ymm15, ymm3 vbroadcasti128 ymm8, xmmword ptr [ROT8+rip] vpshufb ymm12, ymm12, ymm8 vpshufb ymm13, ymm13, ymm8 vpshufb ymm14, ymm14, ymm8 vpshufb ymm15, ymm15, ymm8 vpaddd ymm8, ymm12, ymmword ptr [rsp+0x200] vpaddd ymm9, ymm9, ymm13 vpaddd ymm10, ymm10, ymm14 vpaddd ymm11, ymm11, ymm15 vpxor ymm4, ymm4, ymm8 vpxor ymm5, ymm5, ymm9 vpxor ymm6, ymm6, ymm10 vpxor ymm7, ymm7, ymm11 vmovdqa ymmword ptr [rsp+0x200], ymm8 vpsrld ymm8, ymm4, 7 vpslld ymm4, ymm4, 25 vpor ymm4, ymm4, ymm8 vpsrld ymm8, ymm5, 7 vpslld ymm5, ymm5, 25 vpor ymm5, ymm5, ymm8 vpsrld ymm8, ymm6, 7 vpslld ymm6, ymm6, 25 vpor ymm6, ymm6, ymm8 vpsrld ymm8, ymm7, 7 vpslld ymm7, ymm7, 25 vpor ymm7, ymm7, ymm8 vpaddd ymm0, ymm0, ymmword ptr [rsp+0x80] vpaddd ymm1, ymm1, ymmword ptr [rsp+0x160] vpaddd ymm2, ymm2, ymmword ptr [rsp+0xA0] vpaddd ymm3, ymm3, ymmword ptr [rsp+0x20] vpaddd ymm0, ymm0, ymm5 vpaddd ymm1, ymm1, ymm6 vpaddd ymm2, ymm2, ymm7 vpaddd ymm3, ymm3, ymm4 vpxor ymm15, ymm15, ymm0 vpxor ymm12, ymm12, ymm1 vpxor ymm13, ymm13, ymm2 vpxor ymm14, ymm14, ymm3 vbroadcasti128 ymm8, xmmword ptr [ROT16+rip] vpshufb ymm15, ymm15, ymm8 vpshufb ymm12, ymm12, ymm8 vpshufb ymm13, ymm13, ymm8 vpshufb ymm14, ymm14, ymm8 vpaddd ymm10, ymm10, ymm15 vpaddd ymm11, ymm11, ymm12 vpaddd ymm8, ymm13, ymmword ptr [rsp+0x200] vpaddd ymm9, ymm9, ymm14 vpxor ymm5, ymm5, ymm10 vpxor ymm6, ymm6, ymm11 vpxor ymm7, ymm7, ymm8 vpxor ymm4, ymm4, ymm9 vmovdqa ymmword ptr [rsp+0x200], ymm8 vpsrld ymm8, ymm5, 12 vpslld ymm5, ymm5, 20 vpor ymm5, ymm5, ymm8 vpsrld ymm8, ymm6, 12 vpslld ymm6, ymm6, 20 vpor ymm6, ymm6, ymm8 vpsrld ymm8, ymm7, 12 vpslld ymm7, ymm7, 20 vpor ymm7, ymm7, ymm8 vpsrld ymm8, ymm4, 12 vpslld ymm4, ymm4, 20 vpor ymm4, ymm4, ymm8 vpaddd ymm0, ymm0, ymmword ptr [rsp] vpaddd ymm1, ymm1, ymmword ptr [rsp+0x40] vpaddd ymm2, ymm2, ymmword ptr [rsp+0x100] vpaddd ymm3, ymm3, ymmword ptr [rsp+0xC0] vpaddd ymm0, ymm0, ymm5 vpaddd ymm1, ymm1, ymm6 vpaddd ymm2, ymm2, ymm7 vpaddd ymm3, ymm3, ymm4 vpxor ymm15, ymm15, ymm0 vpxor ymm12, ymm12, ymm1 vpxor ymm13, ymm13, ymm2 vpxor ymm14, ymm14, ymm3 vbroadcasti128 ymm8, xmmword ptr [ROT8+rip] vpshufb ymm15, ymm15, ymm8 vpshufb ymm12, ymm12, ymm8 vpshufb ymm13, ymm13, ymm8 vpshufb ymm14, ymm14, ymm8 vpaddd ymm10, ymm10, ymm15 vpaddd ymm11, ymm11, ymm12 vpaddd ymm8, ymm13, ymmword ptr [rsp+0x200] vpaddd ymm9, ymm9, ymm14 vpxor ymm5, ymm5, ymm10 vpxor ymm6, ymm6, ymm11 vpxor ymm7, ymm7, ymm8 vpxor ymm4, ymm4, ymm9 vmovdqa ymmword ptr [rsp+0x200], ymm8 vpsrld ymm8, ymm5, 7 vpslld ymm5, ymm5, 25 vpor ymm5, ymm5, ymm8 vpsrld ymm8, ymm6, 7 vpslld ymm6, ymm6, 25 vpor ymm6, ymm6, ymm8 vpsrld ymm8, ymm7, 7 vpslld ymm7, ymm7, 25 vpor ymm7, ymm7, ymm8 vpsrld ymm8, ymm4, 7 vpslld ymm4, ymm4, 25 vpor ymm4, ymm4, ymm8 vpaddd ymm0, ymm0, ymmword ptr [rsp+0x180] vpaddd ymm1, ymm1, ymmword ptr [rsp+0x120] vpaddd ymm2, ymm2, ymmword ptr [rsp+0x1E0] vpaddd ymm3, ymm3, ymmword ptr [rsp+0x1C0] vpaddd ymm0, ymm0, ymm4 vpaddd ymm1, ymm1, ymm5 vpaddd ymm2, ymm2, ymm6 vpaddd ymm3, ymm3, ymm7 vpxor ymm12, ymm12, ymm0 vpxor ymm13, ymm13, ymm1 vpxor ymm14, ymm14, ymm2 vpxor ymm15, ymm15, ymm3 vbroadcasti128 ymm8, xmmword ptr [ROT16+rip] vpshufb ymm12, ymm12, ymm8 vpshufb ymm13, ymm13, ymm8 vpshufb ymm14, ymm14, ymm8 vpshufb ymm15, ymm15, ymm8 vpaddd ymm8, ymm12, ymmword ptr [rsp+0x200] vpaddd ymm9, ymm9, ymm13 vpaddd ymm10, ymm10, ymm14 vpaddd ymm11, ymm11, ymm15 vpxor ymm4, ymm4, ymm8 vpxor ymm5, ymm5, ymm9 vpxor ymm6, ymm6, ymm10 vpxor ymm7, ymm7, ymm11 vmovdqa ymmword ptr [rsp+0x200], ymm8 vpsrld ymm8, ymm4, 12 vpslld ymm4, ymm4, 20 vpor ymm4, ymm4, ymm8 vpsrld ymm8, ymm5, 12 vpslld ymm5, ymm5, 20 vpor ymm5, ymm5, ymm8 vpsrld ymm8, ymm6, 12 vpslld ymm6, ymm6, 20 vpor ymm6, ymm6, ymm8 vpsrld ymm8, ymm7, 12 vpslld ymm7, ymm7, 20 vpor ymm7, ymm7, ymm8 vpaddd ymm0, ymm0, ymmword ptr [rsp+0x1A0] vpaddd ymm1, ymm1, ymmword ptr [rsp+0x160] vpaddd ymm2, ymm2, ymmword ptr [rsp+0x140] vpaddd ymm3, ymm3, ymmword ptr [rsp+0x100] vpaddd ymm0, ymm0, ymm4 vpaddd ymm1, ymm1, ymm5 vpaddd ymm2, ymm2, ymm6 vpaddd ymm3, ymm3, ymm7 vpxor ymm12, ymm12, ymm0 vpxor ymm13, ymm13, ymm1 vpxor ymm14, ymm14, ymm2 vpxor ymm15, ymm15, ymm3 vbroadcasti128 ymm8, xmmword ptr [ROT8+rip] vpshufb ymm12, ymm12, ymm8 vpshufb ymm13, ymm13, ymm8 vpshufb ymm14, ymm14, ymm8 vpshufb ymm15, ymm15, ymm8 vpaddd ymm8, ymm12, ymmword ptr [rsp+0x200] vpaddd ymm9, ymm9, ymm13 vpaddd ymm10, ymm10, ymm14 vpaddd ymm11, ymm11, ymm15 vpxor ymm4, ymm4, ymm8 vpxor ymm5, ymm5, ymm9 vpxor ymm6, ymm6, ymm10 vpxor ymm7, ymm7, ymm11 vmovdqa ymmword ptr [rsp+0x200], ymm8 vpsrld ymm8, ymm4, 7 vpslld ymm4, ymm4, 25 vpor ymm4, ymm4, ymm8 vpsrld ymm8, ymm5, 7 vpslld ymm5, ymm5, 25 vpor ymm5, ymm5, ymm8 vpsrld ymm8, ymm6, 7 vpslld ymm6, ymm6, 25 vpor ymm6, ymm6, ymm8 vpsrld ymm8, ymm7, 7 vpslld ymm7, ymm7, 25 vpor ymm7, ymm7, ymm8 vpaddd ymm0, ymm0, ymmword ptr [rsp+0xE0] vpaddd ymm1, ymm1, ymmword ptr [rsp+0xA0] vpaddd ymm2, ymm2, ymmword ptr [rsp] vpaddd ymm3, ymm3, ymmword ptr [rsp+0xC0] vpaddd ymm0, ymm0, ymm5 vpaddd ymm1, ymm1, ymm6 vpaddd ymm2, ymm2, ymm7 vpaddd ymm3, ymm3, ymm4 vpxor ymm15, ymm15, ymm0 vpxor ymm12, ymm12, ymm1 vpxor ymm13, ymm13, ymm2 vpxor ymm14, ymm14, ymm3 vbroadcasti128 ymm8, xmmword ptr [ROT16+rip] vpshufb ymm15, ymm15, ymm8 vpshufb ymm12, ymm12, ymm8 vpshufb ymm13, ymm13, ymm8 vpshufb ymm14, ymm14, ymm8 vpaddd ymm10, ymm10, ymm15 vpaddd ymm11, ymm11, ymm12 vpaddd ymm8, ymm13, ymmword ptr [rsp+0x200] vpaddd ymm9, ymm9, ymm14 vpxor ymm5, ymm5, ymm10 vpxor ymm6, ymm6, ymm11 vpxor ymm7, ymm7, ymm8 vpxor ymm4, ymm4, ymm9 vmovdqa ymmword ptr [rsp+0x200], ymm8 vpsrld ymm8, ymm5, 12 vpslld ymm5, ymm5, 20 vpor ymm5, ymm5, ymm8 vpsrld ymm8, ymm6, 12 vpslld ymm6, ymm6, 20 vpor ymm6, ymm6, ymm8 vpsrld ymm8, ymm7, 12 vpslld ymm7, ymm7, 20 vpor ymm7, ymm7, ymm8 vpsrld ymm8, ymm4, 12 vpslld ymm4, ymm4, 20 vpor ymm4, ymm4, ymm8 vpaddd ymm0, ymm0, ymmword ptr [rsp+0x40] vpaddd ymm1, ymm1, ymmword ptr [rsp+0x60] vpaddd ymm2, ymm2, ymmword ptr [rsp+0x20] vpaddd ymm3, ymm3, ymmword ptr [rsp+0x80] vpaddd ymm0, ymm0, ymm5 vpaddd ymm1, ymm1, ymm6 vpaddd ymm2, ymm2, ymm7 vpaddd ymm3, ymm3, ymm4 vpxor ymm15, ymm15, ymm0 vpxor ymm12, ymm12, ymm1 vpxor ymm13, ymm13, ymm2 vpxor ymm14, ymm14, ymm3 vbroadcasti128 ymm8, xmmword ptr [ROT8+rip] vpshufb ymm15, ymm15, ymm8 vpshufb ymm12, ymm12, ymm8 vpshufb ymm13, ymm13, ymm8 vpshufb ymm14, ymm14, ymm8 vpaddd ymm10, ymm10, ymm15 vpaddd ymm11, ymm11, ymm12 vpaddd ymm8, ymm13, ymmword ptr [rsp+0x200] vpaddd ymm9, ymm9, ymm14 vpxor ymm5, ymm5, ymm10 vpxor ymm6, ymm6, ymm11 vpxor ymm7, ymm7, ymm8 vpxor ymm4, ymm4, ymm9 vmovdqa ymmword ptr [rsp+0x200], ymm8 vpsrld ymm8, ymm5, 7 vpslld ymm5, ymm5, 25 vpor ymm5, ymm5, ymm8 vpsrld ymm8, ymm6, 7 vpslld ymm6, ymm6, 25 vpor ymm6, ymm6, ymm8 vpsrld ymm8, ymm7, 7 vpslld ymm7, ymm7, 25 vpor ymm7, ymm7, ymm8 vpsrld ymm8, ymm4, 7 vpslld ymm4, ymm4, 25 vpor ymm4, ymm4, ymm8 vpaddd ymm0, ymm0, ymmword ptr [rsp+0x120] vpaddd ymm1, ymm1, ymmword ptr [rsp+0x160] vpaddd ymm2, ymm2, ymmword ptr [rsp+0x100] vpaddd ymm3, ymm3, ymmword ptr [rsp+0x1E0] vpaddd ymm0, ymm0, ymm4 vpaddd ymm1, ymm1, ymm5 vpaddd ymm2, ymm2, ymm6 vpaddd ymm3, ymm3, ymm7 vpxor ymm12, ymm12, ymm0 vpxor ymm13, ymm13, ymm1 vpxor ymm14, ymm14, ymm2 vpxor ymm15, ymm15, ymm3 vbroadcasti128 ymm8, xmmword ptr [ROT16+rip] vpshufb ymm12, ymm12, ymm8 vpshufb ymm13, ymm13, ymm8 vpshufb ymm14, ymm14, ymm8 vpshufb ymm15, ymm15, ymm8 vpaddd ymm8, ymm12, ymmword ptr [rsp+0x200] vpaddd ymm9, ymm9, ymm13 vpaddd ymm10, ymm10, ymm14 vpaddd ymm11, ymm11, ymm15 vpxor ymm4, ymm4, ymm8 vpxor ymm5, ymm5, ymm9 vpxor ymm6, ymm6, ymm10 vpxor ymm7, ymm7, ymm11 vmovdqa ymmword ptr [rsp+0x200], ymm8 vpsrld ymm8, ymm4, 12 vpslld ymm4, ymm4, 20 vpor ymm4, ymm4, ymm8 vpsrld ymm8, ymm5, 12 vpslld ymm5, ymm5, 20 vpor ymm5, ymm5, ymm8 vpsrld ymm8, ymm6, 12 vpslld ymm6, ymm6, 20 vpor ymm6, ymm6, ymm8 vpsrld ymm8, ymm7, 12 vpslld ymm7, ymm7, 20 vpor ymm7, ymm7, ymm8 vpaddd ymm0, ymm0, ymmword ptr [rsp+0x1C0] vpaddd ymm1, ymm1, ymmword ptr [rsp+0xA0] vpaddd ymm2, ymm2, ymmword ptr [rsp+0x180] vpaddd ymm3, ymm3, ymmword ptr [rsp+0x20] vpaddd ymm0, ymm0, ymm4 vpaddd ymm1, ymm1, ymm5 vpaddd ymm2, ymm2, ymm6 vpaddd ymm3, ymm3, ymm7 vpxor ymm12, ymm12, ymm0 vpxor ymm13, ymm13, ymm1 vpxor ymm14, ymm14, ymm2 vpxor ymm15, ymm15, ymm3 vbroadcasti128 ymm8, xmmword ptr [ROT8+rip] vpshufb ymm12, ymm12, ymm8 vpshufb ymm13, ymm13, ymm8 vpshufb ymm14, ymm14, ymm8 vpshufb ymm15, ymm15, ymm8 vpaddd ymm8, ymm12, ymmword ptr [rsp+0x200] vpaddd ymm9, ymm9, ymm13 vpaddd ymm10, ymm10, ymm14 vpaddd ymm11, ymm11, ymm15 vpxor ymm4, ymm4, ymm8 vpxor ymm5, ymm5, ymm9 vpxor ymm6, ymm6, ymm10 vpxor ymm7, ymm7, ymm11 vmovdqa ymmword ptr [rsp+0x200], ymm8 vpsrld ymm8, ymm4, 7 vpslld ymm4, ymm4, 25 vpor ymm4, ymm4, ymm8 vpsrld ymm8, ymm5, 7 vpslld ymm5, ymm5, 25 vpor ymm5, ymm5, ymm8 vpsrld ymm8, ymm6, 7 vpslld ymm6, ymm6, 25 vpor ymm6, ymm6, ymm8 vpsrld ymm8, ymm7, 7 vpslld ymm7, ymm7, 25 vpor ymm7, ymm7, ymm8 vpaddd ymm0, ymm0, ymmword ptr [rsp+0x1A0] vpaddd ymm1, ymm1, ymmword ptr [rsp] vpaddd ymm2, ymm2, ymmword ptr [rsp+0x40] vpaddd ymm3, ymm3, ymmword ptr [rsp+0x80] vpaddd ymm0, ymm0, ymm5 vpaddd ymm1, ymm1, ymm6 vpaddd ymm2, ymm2, ymm7 vpaddd ymm3, ymm3, ymm4 vpxor ymm15, ymm15, ymm0 vpxor ymm12, ymm12, ymm1 vpxor ymm13, ymm13, ymm2 vpxor ymm14, ymm14, ymm3 vbroadcasti128 ymm8, xmmword ptr [ROT16+rip] vpshufb ymm15, ymm15, ymm8 vpshufb ymm12, ymm12, ymm8 vpshufb ymm13, ymm13, ymm8 vpshufb ymm14, ymm14, ymm8 vpaddd ymm10, ymm10, ymm15 vpaddd ymm11, ymm11, ymm12 vpaddd ymm8, ymm13, ymmword ptr [rsp+0x200] vpaddd ymm9, ymm9, ymm14 vpxor ymm5, ymm5, ymm10 vpxor ymm6, ymm6, ymm11 vpxor ymm7, ymm7, ymm8 vpxor ymm4, ymm4, ymm9 vmovdqa ymmword ptr [rsp+0x200], ymm8 vpsrld ymm8, ymm5, 12 vpslld ymm5, ymm5, 20 vpor ymm5, ymm5, ymm8 vpsrld ymm8, ymm6, 12 vpslld ymm6, ymm6, 20 vpor ymm6, ymm6, ymm8 vpsrld ymm8, ymm7, 12 vpslld ymm7, ymm7, 20 vpor ymm7, ymm7, ymm8 vpsrld ymm8, ymm4, 12 vpslld ymm4, ymm4, 20 vpor ymm4, ymm4, ymm8 vpaddd ymm0, ymm0, ymmword ptr [rsp+0x60] vpaddd ymm1, ymm1, ymmword ptr [rsp+0x140] vpaddd ymm2, ymm2, ymmword ptr [rsp+0xC0] vpaddd ymm3, ymm3, ymmword ptr [rsp+0xE0] vpaddd ymm0, ymm0, ymm5 vpaddd ymm1, ymm1, ymm6 vpaddd ymm2, ymm2, ymm7 vpaddd ymm3, ymm3, ymm4 vpxor ymm15, ymm15, ymm0 vpxor ymm12, ymm12, ymm1 vpxor ymm13, ymm13, ymm2 vpxor ymm14, ymm14, ymm3 vbroadcasti128 ymm8, xmmword ptr [ROT8+rip] vpshufb ymm15, ymm15, ymm8 vpshufb ymm12, ymm12, ymm8 vpshufb ymm13, ymm13, ymm8 vpshufb ymm14, ymm14, ymm8 vpaddd ymm10, ymm10, ymm15 vpaddd ymm11, ymm11, ymm12 vpaddd ymm8, ymm13, ymmword ptr [rsp+0x200] vpaddd ymm9, ymm9, ymm14 vpxor ymm5, ymm5, ymm10 vpxor ymm6, ymm6, ymm11 vpxor ymm7, ymm7, ymm8 vpxor ymm4, ymm4, ymm9 vmovdqa ymmword ptr [rsp+0x200], ymm8 vpsrld ymm8, ymm5, 7 vpslld ymm5, ymm5, 25 vpor ymm5, ymm5, ymm8 vpsrld ymm8, ymm6, 7 vpslld ymm6, ymm6, 25 vpor ymm6, ymm6, ymm8 vpsrld ymm8, ymm7, 7 vpslld ymm7, ymm7, 25 vpor ymm7, ymm7, ymm8 vpsrld ymm8, ymm4, 7 vpslld ymm4, ymm4, 25 vpor ymm4, ymm4, ymm8 vpaddd ymm0, ymm0, ymmword ptr [rsp+0x160] vpaddd ymm1, ymm1, ymmword ptr [rsp+0xA0] vpaddd ymm2, ymm2, ymmword ptr [rsp+0x20] vpaddd ymm3, ymm3, ymmword ptr [rsp+0x100] vpaddd ymm0, ymm0, ymm4 vpaddd ymm1, ymm1, ymm5 vpaddd ymm2, ymm2, ymm6 vpaddd ymm3, ymm3, ymm7 vpxor ymm12, ymm12, ymm0 vpxor ymm13, ymm13, ymm1 vpxor ymm14, ymm14, ymm2 vpxor ymm15, ymm15, ymm3 vbroadcasti128 ymm8, xmmword ptr [ROT16+rip] vpshufb ymm12, ymm12, ymm8 vpshufb ymm13, ymm13, ymm8 vpshufb ymm14, ymm14, ymm8 vpshufb ymm15, ymm15, ymm8 vpaddd ymm8, ymm12, ymmword ptr [rsp+0x200] vpaddd ymm9, ymm9, ymm13 vpaddd ymm10, ymm10, ymm14 vpaddd ymm11, ymm11, ymm15 vpxor ymm4, ymm4, ymm8 vpxor ymm5, ymm5, ymm9 vpxor ymm6, ymm6, ymm10 vpxor ymm7, ymm7, ymm11 vmovdqa ymmword ptr [rsp+0x200], ymm8 vpsrld ymm8, ymm4, 12 vpslld ymm4, ymm4, 20 vpor ymm4, ymm4, ymm8 vpsrld ymm8, ymm5, 12 vpslld ymm5, ymm5, 20 vpor ymm5, ymm5, ymm8 vpsrld ymm8, ymm6, 12 vpslld ymm6, ymm6, 20 vpor ymm6, ymm6, ymm8 vpsrld ymm8, ymm7, 12 vpslld ymm7, ymm7, 20 vpor ymm7, ymm7, ymm8 vpaddd ymm0, ymm0, ymmword ptr [rsp+0x1E0] vpaddd ymm1, ymm1, ymmword ptr [rsp] vpaddd ymm2, ymm2, ymmword ptr [rsp+0x120] vpaddd ymm3, ymm3, ymmword ptr [rsp+0xC0] vpaddd ymm0, ymm0, ymm4 vpaddd ymm1, ymm1, ymm5 vpaddd ymm2, ymm2, ymm6 vpaddd ymm3, ymm3, ymm7 vpxor ymm12, ymm12, ymm0 vpxor ymm13, ymm13, ymm1 vpxor ymm14, ymm14, ymm2 vpxor ymm15, ymm15, ymm3 vbroadcasti128 ymm8, xmmword ptr [ROT8+rip] vpshufb ymm12, ymm12, ymm8 vpshufb ymm13, ymm13, ymm8 vpshufb ymm14, ymm14, ymm8 vpshufb ymm15, ymm15, ymm8 vpaddd ymm8, ymm12, ymmword ptr [rsp+0x200] vpaddd ymm9, ymm9, ymm13 vpaddd ymm10, ymm10, ymm14 vpaddd ymm11, ymm11, ymm15 vpxor ymm4, ymm4, ymm8 vpxor ymm5, ymm5, ymm9 vpxor ymm6, ymm6, ymm10 vpxor ymm7, ymm7, ymm11 vmovdqa ymmword ptr [rsp+0x200], ymm8 vpsrld ymm8, ymm4, 7 vpslld ymm4, ymm4, 25 vpor ymm4, ymm4, ymm8 vpsrld ymm8, ymm5, 7 vpslld ymm5, ymm5, 25 vpor ymm5, ymm5, ymm8 vpsrld ymm8, ymm6, 7 vpslld ymm6, ymm6, 25 vpor ymm6, ymm6, ymm8 vpsrld ymm8, ymm7, 7 vpslld ymm7, ymm7, 25 vpor ymm7, ymm7, ymm8 vpaddd ymm0, ymm0, ymmword ptr [rsp+0x1C0] vpaddd ymm1, ymm1, ymmword ptr [rsp+0x40] vpaddd ymm2, ymm2, ymmword ptr [rsp+0x60] vpaddd ymm3, ymm3, ymmword ptr [rsp+0xE0] vpaddd ymm0, ymm0, ymm5 vpaddd ymm1, ymm1, ymm6 vpaddd ymm2, ymm2, ymm7 vpaddd ymm3, ymm3, ymm4 vpxor ymm15, ymm15, ymm0 vpxor ymm12, ymm12, ymm1 vpxor ymm13, ymm13, ymm2 vpxor ymm14, ymm14, ymm3 vbroadcasti128 ymm8, xmmword ptr [ROT16+rip] vpshufb ymm15, ymm15, ymm8 vpshufb ymm12, ymm12, ymm8 vpshufb ymm13, ymm13, ymm8 vpshufb ymm14, ymm14, ymm8 vpaddd ymm10, ymm10, ymm15 vpaddd ymm11, ymm11, ymm12 vpaddd ymm8, ymm13, ymmword ptr [rsp+0x200] vpaddd ymm9, ymm9, ymm14 vpxor ymm5, ymm5, ymm10 vpxor ymm6, ymm6, ymm11 vpxor ymm7, ymm7, ymm8 vpxor ymm4, ymm4, ymm9 vmovdqa ymmword ptr [rsp+0x200], ymm8 vpsrld ymm8, ymm5, 12 vpslld ymm5, ymm5, 20 vpor ymm5, ymm5, ymm8 vpsrld ymm8, ymm6, 12 vpslld ymm6, ymm6, 20 vpor ymm6, ymm6, ymm8 vpsrld ymm8, ymm7, 12 vpslld ymm7, ymm7, 20 vpor ymm7, ymm7, ymm8 vpsrld ymm8, ymm4, 12 vpslld ymm4, ymm4, 20 vpor ymm4, ymm4, ymm8 vpaddd ymm0, ymm0, ymmword ptr [rsp+0x140] vpaddd ymm1, ymm1, ymmword ptr [rsp+0x180] vpaddd ymm2, ymm2, ymmword ptr [rsp+0x80] vpaddd ymm3, ymm3, ymmword ptr [rsp+0x1A0] vpaddd ymm0, ymm0, ymm5 vpaddd ymm1, ymm1, ymm6 vpaddd ymm2, ymm2, ymm7 vpaddd ymm3, ymm3, ymm4 vpxor ymm15, ymm15, ymm0 vpxor ymm12, ymm12, ymm1 vpxor ymm13, ymm13, ymm2 vpxor ymm14, ymm14, ymm3 vbroadcasti128 ymm8, xmmword ptr [ROT8+rip] vpshufb ymm15, ymm15, ymm8 vpshufb ymm12, ymm12, ymm8 vpshufb ymm13, ymm13, ymm8 vpshufb ymm14, ymm14, ymm8 vpaddd ymm10, ymm10, ymm15 vpaddd ymm11, ymm11, ymm12 vpaddd ymm8, ymm13, ymmword ptr [rsp+0x200] vpaddd ymm9, ymm9, ymm14 vpxor ymm5, ymm5, ymm10 vpxor ymm6, ymm6, ymm11 vpxor ymm7, ymm7, ymm8 vpxor ymm4, ymm4, ymm9 vpxor ymm0, ymm0, ymm8 vpxor ymm1, ymm1, ymm9 vpxor ymm2, ymm2, ymm10 vpxor ymm3, ymm3, ymm11 vpsrld ymm8, ymm5, 7 vpslld ymm5, ymm5, 25 vpor ymm5, ymm5, ymm8 vpsrld ymm8, ymm6, 7 vpslld ymm6, ymm6, 25 vpor ymm6, ymm6, ymm8 vpsrld ymm8, ymm7, 7 vpslld ymm7, ymm7, 25 vpor ymm7, ymm7, ymm8 vpsrld ymm8, ymm4, 7 vpslld ymm4, ymm4, 25 vpor ymm4, ymm4, ymm8 vpxor ymm4, ymm4, ymm12 vpxor ymm5, ymm5, ymm13 vpxor ymm6, ymm6, ymm14 vpxor ymm7, ymm7, ymm15 movzx eax, byte ptr [rbp+0x38] jne 9b mov rbx, qword ptr [rbp+0x50] vunpcklps ymm8, ymm0, ymm1 vunpcklps ymm9, ymm2, ymm3 vunpckhps ymm10, ymm0, ymm1 vunpcklps ymm11, ymm4, ymm5 vunpcklps ymm0, ymm6, ymm7 vshufps ymm12, ymm8, ymm9, 78 vblendps ymm1, ymm8, ymm12, 0xCC vshufps ymm8, ymm11, ymm0, 78 vunpckhps ymm13, ymm2, ymm3 vblendps ymm2, ymm11, ymm8, 0xCC vblendps ymm3, ymm12, ymm9, 0xCC vperm2f128 ymm12, ymm1, ymm2, 0x20 vmovups ymmword ptr [rbx], ymm12 vunpckhps ymm14, ymm4, ymm5 vblendps ymm4, ymm8, ymm0, 0xCC vunpckhps ymm15, ymm6, ymm7 vperm2f128 ymm7, ymm3, ymm4, 0x20 vmovups ymmword ptr [rbx+0x20], ymm7 vshufps ymm5, ymm10, ymm13, 78 vblendps ymm6, ymm5, ymm13, 0xCC vshufps ymm13, ymm14, ymm15, 78 vblendps ymm10, ymm10, ymm5, 0xCC vblendps ymm14, ymm14, ymm13, 0xCC vperm2f128 ymm8, ymm10, ymm14, 0x20 vmovups ymmword ptr [rbx+0x40], ymm8 vblendps ymm15, ymm13, ymm15, 0xCC vperm2f128 ymm13, ymm6, ymm15, 0x20 vmovups ymmword ptr [rbx+0x60], ymm13 vperm2f128 ymm9, ymm1, ymm2, 0x31 vperm2f128 ymm11, ymm3, ymm4, 0x31 vmovups ymmword ptr [rbx+0x80], ymm9 vperm2f128 ymm14, ymm10, ymm14, 0x31 vperm2f128 ymm15, ymm6, ymm15, 0x31 vmovups ymmword ptr [rbx+0xA0], ymm11 vmovups ymmword ptr [rbx+0xC0], ymm14 vmovups ymmword ptr [rbx+0xE0], ymm15 vmovdqa ymm0, ymmword ptr [rsp+0x220] vpaddd ymm1, ymm0, ymmword ptr [rsp+0x240] vmovdqa ymmword ptr [rsp+0x240], ymm1 vpxor ymm0, ymm0, ymmword ptr [CMP_MSB_MASK+rip] vpxor ymm2, ymm1, ymmword ptr [CMP_MSB_MASK+rip] vpcmpgtd ymm2, ymm0, ymm2 vmovdqa ymm0, ymmword ptr [rsp+0x260] vpsubd ymm2, ymm0, ymm2 vmovdqa ymmword ptr [rsp+0x260], ymm2 add rdi, 64 add rbx, 256 mov qword ptr [rbp+0x50], rbx sub rsi, 8 cmp rsi, 8 jnc 2b test rsi, rsi jnz 3f 4: vzeroupper mov rsp, rbp pop rbp pop rbx pop r12 pop r13 pop r14 pop r15 ret .p2align 5 3: mov rbx, qword ptr [rbp+0x50] mov r15, qword ptr [rsp+0x2A0] movzx r13d, byte ptr [rbp+0x38] movzx r12d, byte ptr [rbp+0x48] test rsi, 0x4 je 3f vbroadcasti128 ymm0, xmmword ptr [rcx] vbroadcasti128 ymm1, xmmword ptr [rcx+0x10] vmovdqa ymm8, ymm0 vmovdqa ymm9, ymm1 vbroadcasti128 ymm12, xmmword ptr [rsp+0x240] vbroadcasti128 ymm13, xmmword ptr [rsp+0x260] vpunpckldq ymm14, ymm12, ymm13 vpunpckhdq ymm15, ymm12, ymm13 vpermq ymm14, ymm14, 0x50 vpermq ymm15, ymm15, 0x50 vbroadcasti128 ymm12, xmmword ptr [BLAKE3_BLOCK_LEN+rip] vpblendd ymm14, ymm14, ymm12, 0x44 vpblendd ymm15, ymm15, ymm12, 0x44 vmovdqa ymmword ptr [rsp], ymm14 vmovdqa ymmword ptr [rsp+0x20], ymm15 mov r8, qword ptr [rdi] mov r9, qword ptr [rdi+0x8] mov r10, qword ptr [rdi+0x10] mov r11, qword ptr [rdi+0x18] movzx eax, byte ptr [rbp+0x40] or eax, r13d xor edx, edx .p2align 5 2: mov r14d, eax or eax, r12d add rdx, 64 cmp rdx, r15 cmovne eax, r14d mov dword ptr [rsp+0x200], eax vmovups ymm2, ymmword ptr [r8+rdx-0x40] vinsertf128 ymm2, ymm2, xmmword ptr [r9+rdx-0x40], 0x01 vmovups ymm3, ymmword ptr [r8+rdx-0x30] vinsertf128 ymm3, ymm3, xmmword ptr [r9+rdx-0x30], 0x01 vshufps ymm4, ymm2, ymm3, 136 vshufps ymm5, ymm2, ymm3, 221 vmovups ymm2, ymmword ptr [r8+rdx-0x20] vinsertf128 ymm2, ymm2, xmmword ptr [r9+rdx-0x20], 0x01 vmovups ymm3, ymmword ptr [r8+rdx-0x10] vinsertf128 ymm3, ymm3, xmmword ptr [r9+rdx-0x10], 0x01 vshufps ymm6, ymm2, ymm3, 136 vshufps ymm7, ymm2, ymm3, 221 vpshufd ymm6, ymm6, 0x93 vpshufd ymm7, ymm7, 0x93 vmovups ymm10, ymmword ptr [r10+rdx-0x40] vinsertf128 ymm10, ymm10, xmmword ptr [r11+rdx-0x40], 0x01 vmovups ymm11, ymmword ptr [r10+rdx-0x30] vinsertf128 ymm11, ymm11, xmmword ptr [r11+rdx-0x30], 0x01 vshufps ymm12, ymm10, ymm11, 136 vshufps ymm13, ymm10, ymm11, 221 vmovups ymm10, ymmword ptr [r10+rdx-0x20] vinsertf128 ymm10, ymm10, xmmword ptr [r11+rdx-0x20], 0x01 vmovups ymm11, ymmword ptr [r10+rdx-0x10] vinsertf128 ymm11, ymm11, xmmword ptr [r11+rdx-0x10], 0x01 vshufps ymm14, ymm10, ymm11, 136 vshufps ymm15, ymm10, ymm11, 221 vpshufd ymm14, ymm14, 0x93 vpshufd ymm15, ymm15, 0x93 prefetcht0 [r8+rdx+0x80] prefetcht0 [r9+rdx+0x80] prefetcht0 [r10+rdx+0x80] prefetcht0 [r11+rdx+0x80] vpbroadcastd ymm2, dword ptr [rsp+0x200] vmovdqa ymm3, ymmword ptr [rsp] vmovdqa ymm11, ymmword ptr [rsp+0x20] vpblendd ymm3, ymm3, ymm2, 0x88 vpblendd ymm11, ymm11, ymm2, 0x88 vbroadcasti128 ymm2, xmmword ptr [BLAKE3_IV+rip] vmovdqa ymm10, ymm2 mov al, 7 9: vpaddd ymm0, ymm0, ymm4 vpaddd ymm8, ymm8, ymm12 vmovdqa ymmword ptr [rsp+0x40], ymm4 nop vmovdqa ymmword ptr [rsp+0x60], ymm12 nop vpaddd ymm0, ymm0, ymm1 vpaddd ymm8, ymm8, ymm9 vpxor ymm3, ymm3, ymm0 vpxor ymm11, ymm11, ymm8 vbroadcasti128 ymm4, xmmword ptr [ROT16+rip] vpshufb ymm3, ymm3, ymm4 vpshufb ymm11, ymm11, ymm4 vpaddd ymm2, ymm2, ymm3 vpaddd ymm10, ymm10, ymm11 vpxor ymm1, ymm1, ymm2 vpxor ymm9, ymm9, ymm10 vpsrld ymm4, ymm1, 12 vpslld ymm1, ymm1, 20 vpor ymm1, ymm1, ymm4 vpsrld ymm4, ymm9, 12 vpslld ymm9, ymm9, 20 vpor ymm9, ymm9, ymm4 vpaddd ymm0, ymm0, ymm5 vpaddd ymm8, ymm8, ymm13 vpaddd ymm0, ymm0, ymm1 vpaddd ymm8, ymm8, ymm9 vmovdqa ymmword ptr [rsp+0x80], ymm5 vmovdqa ymmword ptr [rsp+0xA0], ymm13 vpxor ymm3, ymm3, ymm0 vpxor ymm11, ymm11, ymm8 vbroadcasti128 ymm4, xmmword ptr [ROT8+rip] vpshufb ymm3, ymm3, ymm4 vpshufb ymm11, ymm11, ymm4 vpaddd ymm2, ymm2, ymm3 vpaddd ymm10, ymm10, ymm11 vpxor ymm1, ymm1, ymm2 vpxor ymm9, ymm9, ymm10 vpsrld ymm4, ymm1, 7 vpslld ymm1, ymm1, 25 vpor ymm1, ymm1, ymm4 vpsrld ymm4, ymm9, 7 vpslld ymm9, ymm9, 25 vpor ymm9, ymm9, ymm4 vpshufd ymm0, ymm0, 0x93 vpshufd ymm8, ymm8, 0x93 vpshufd ymm3, ymm3, 0x4E vpshufd ymm11, ymm11, 0x4E vpshufd ymm2, ymm2, 0x39 vpshufd ymm10, ymm10, 0x39 vpaddd ymm0, ymm0, ymm6 vpaddd ymm8, ymm8, ymm14 vpaddd ymm0, ymm0, ymm1 vpaddd ymm8, ymm8, ymm9 vpxor ymm3, ymm3, ymm0 vpxor ymm11, ymm11, ymm8 vbroadcasti128 ymm4, xmmword ptr [ROT16+rip] vpshufb ymm3, ymm3, ymm4 vpshufb ymm11, ymm11, ymm4 vpaddd ymm2, ymm2, ymm3 vpaddd ymm10, ymm10, ymm11 vpxor ymm1, ymm1, ymm2 vpxor ymm9, ymm9, ymm10 vpsrld ymm4, ymm1, 12 vpslld ymm1, ymm1, 20 vpor ymm1, ymm1, ymm4 vpsrld ymm4, ymm9, 12 vpslld ymm9, ymm9, 20 vpor ymm9, ymm9, ymm4 vpaddd ymm0, ymm0, ymm7 vpaddd ymm8, ymm8, ymm15 vpaddd ymm0, ymm0, ymm1 vpaddd ymm8, ymm8, ymm9 vpxor ymm3, ymm3, ymm0 vpxor ymm11, ymm11, ymm8 vbroadcasti128 ymm4, xmmword ptr [ROT8+rip] vpshufb ymm3, ymm3, ymm4 vpshufb ymm11, ymm11, ymm4 vpaddd ymm2, ymm2, ymm3 vpaddd ymm10, ymm10, ymm11 vpxor ymm1, ymm1, ymm2 vpxor ymm9, ymm9, ymm10 vpsrld ymm4, ymm1, 7 vpslld ymm1, ymm1, 25 vpor ymm1, ymm1, ymm4 vpsrld ymm4, ymm9, 7 vpslld ymm9, ymm9, 25 vpor ymm9, ymm9, ymm4 vpshufd ymm0, ymm0, 0x39 vpshufd ymm8, ymm8, 0x39 vpshufd ymm3, ymm3, 0x4E vpshufd ymm11, ymm11, 0x4E vpshufd ymm2, ymm2, 0x93 vpshufd ymm10, ymm10, 0x93 dec al je 9f vmovdqa ymm4, ymmword ptr [rsp+0x40] vmovdqa ymm5, ymmword ptr [rsp+0x80] vshufps ymm12, ymm4, ymm5, 214 vpshufd ymm13, ymm4, 0x0F vpshufd ymm4, ymm12, 0x39 vshufps ymm12, ymm6, ymm7, 250 vpblendd ymm13, ymm13, ymm12, 0xAA vpunpcklqdq ymm12, ymm7, ymm5 vpblendd ymm12, ymm12, ymm6, 0x88 vpshufd ymm12, ymm12, 0x78 vpunpckhdq ymm5, ymm5, ymm7 vpunpckldq ymm6, ymm6, ymm5 vpshufd ymm7, ymm6, 0x1E vmovdqa ymmword ptr [rsp+0x40], ymm13 vmovdqa ymmword ptr [rsp+0x80], ymm12 vmovdqa ymm12, ymmword ptr [rsp+0x60] vmovdqa ymm13, ymmword ptr [rsp+0xA0] vshufps ymm5, ymm12, ymm13, 214 vpshufd ymm6, ymm12, 0x0F vpshufd ymm12, ymm5, 0x39 vshufps ymm5, ymm14, ymm15, 250 vpblendd ymm6, ymm6, ymm5, 0xAA vpunpcklqdq ymm5, ymm15, ymm13 vpblendd ymm5, ymm5, ymm14, 0x88 vpshufd ymm5, ymm5, 0x78 vpunpckhdq ymm13, ymm13, ymm15 vpunpckldq ymm14, ymm14, ymm13 vpshufd ymm15, ymm14, 0x1E vmovdqa ymm13, ymm6 vmovdqa ymm14, ymm5 vmovdqa ymm5, ymmword ptr [rsp+0x40] vmovdqa ymm6, ymmword ptr [rsp+0x80] jmp 9b 9: vpxor ymm0, ymm0, ymm2 vpxor ymm1, ymm1, ymm3 vpxor ymm8, ymm8, ymm10 vpxor ymm9, ymm9, ymm11 mov eax, r13d cmp rdx, r15 jne 2b vmovdqu xmmword ptr [rbx], xmm0 vmovdqu xmmword ptr [rbx+0x10], xmm1 vextracti128 xmmword ptr [rbx+0x20], ymm0, 0x01 vextracti128 xmmword ptr [rbx+0x30], ymm1, 0x01 vmovdqu xmmword ptr [rbx+0x40], xmm8 vmovdqu xmmword ptr [rbx+0x50], xmm9 vextracti128 xmmword ptr [rbx+0x60], ymm8, 0x01 vextracti128 xmmword ptr [rbx+0x70], ymm9, 0x01 vmovaps xmm8, xmmword ptr [rsp+0x280] vmovaps xmm0, xmmword ptr [rsp+0x240] vmovaps xmm1, xmmword ptr [rsp+0x250] vmovaps xmm2, xmmword ptr [rsp+0x260] vmovaps xmm3, xmmword ptr [rsp+0x270] vblendvps xmm0, xmm0, xmm1, xmm8 vblendvps xmm2, xmm2, xmm3, xmm8 vmovaps xmmword ptr [rsp+0x240], xmm0 vmovaps xmmword ptr [rsp+0x260], xmm2 add rbx, 128 add rdi, 32 sub rsi, 4 3: test rsi, 0x2 je 3f vbroadcasti128 ymm0, xmmword ptr [rcx] vbroadcasti128 ymm1, xmmword ptr [rcx+0x10] vmovd xmm13, dword ptr [rsp+0x240] vpinsrd xmm13, xmm13, dword ptr [rsp+0x260], 1 vpinsrd xmm13, xmm13, dword ptr [BLAKE3_BLOCK_LEN+rip], 2 vmovd xmm14, dword ptr [rsp+0x244] vpinsrd xmm14, xmm14, dword ptr [rsp+0x264], 1 vpinsrd xmm14, xmm14, dword ptr [BLAKE3_BLOCK_LEN+rip], 2 vinserti128 ymm13, ymm13, xmm14, 0x01 vbroadcasti128 ymm14, xmmword ptr [ROT16+rip] vbroadcasti128 ymm15, xmmword ptr [ROT8+rip] mov r8, qword ptr [rdi] mov r9, qword ptr [rdi+0x8] movzx eax, byte ptr [rbp+0x40] or eax, r13d xor edx, edx .p2align 5 2: mov r14d, eax or eax, r12d add rdx, 64 cmp rdx, r15 cmovne eax, r14d mov dword ptr [rsp+0x200], eax vbroadcasti128 ymm2, xmmword ptr [BLAKE3_IV+rip] vpbroadcastd ymm8, dword ptr [rsp+0x200] vpblendd ymm3, ymm13, ymm8, 0x88 vmovups ymm8, ymmword ptr [r8+rdx-0x40] vinsertf128 ymm8, ymm8, xmmword ptr [r9+rdx-0x40], 0x01 vmovups ymm9, ymmword ptr [r8+rdx-0x30] vinsertf128 ymm9, ymm9, xmmword ptr [r9+rdx-0x30], 0x01 vshufps ymm4, ymm8, ymm9, 136 vshufps ymm5, ymm8, ymm9, 221 vmovups ymm8, ymmword ptr [r8+rdx-0x20] vinsertf128 ymm8, ymm8, xmmword ptr [r9+rdx-0x20], 0x01 vmovups ymm9, ymmword ptr [r8+rdx-0x10] vinsertf128 ymm9, ymm9, xmmword ptr [r9+rdx-0x10], 0x01 vshufps ymm6, ymm8, ymm9, 136 vshufps ymm7, ymm8, ymm9, 221 vpshufd ymm6, ymm6, 0x93 vpshufd ymm7, ymm7, 0x93 mov al, 7 9: vpaddd ymm0, ymm0, ymm4 vpaddd ymm0, ymm0, ymm1 vpxor ymm3, ymm3, ymm0 vpshufb ymm3, ymm3, ymm14 vpaddd ymm2, ymm2, ymm3 vpxor ymm1, ymm1, ymm2 vpsrld ymm8, ymm1, 12 vpslld ymm1, ymm1, 20 vpor ymm1, ymm1, ymm8 vpaddd ymm0, ymm0, ymm5 vpaddd ymm0, ymm0, ymm1 vpxor ymm3, ymm3, ymm0 vpshufb ymm3, ymm3, ymm15 vpaddd ymm2, ymm2, ymm3 vpxor ymm1, ymm1, ymm2 vpsrld ymm8, ymm1, 7 vpslld ymm1, ymm1, 25 vpor ymm1, ymm1, ymm8 vpshufd ymm0, ymm0, 0x93 vpshufd ymm3, ymm3, 0x4E vpshufd ymm2, ymm2, 0x39 vpaddd ymm0, ymm0, ymm6 vpaddd ymm0, ymm0, ymm1 vpxor ymm3, ymm3, ymm0 vpshufb ymm3, ymm3, ymm14 vpaddd ymm2, ymm2, ymm3 vpxor ymm1, ymm1, ymm2 vpsrld ymm8, ymm1, 12 vpslld ymm1, ymm1, 20 vpor ymm1, ymm1, ymm8 vpaddd ymm0, ymm0, ymm7 vpaddd ymm0, ymm0, ymm1 vpxor ymm3, ymm3, ymm0 vpshufb ymm3, ymm3, ymm15 vpaddd ymm2, ymm2, ymm3 vpxor ymm1, ymm1, ymm2 vpsrld ymm8, ymm1, 7 vpslld ymm1, ymm1, 25 vpor ymm1, ymm1, ymm8 vpshufd ymm0, ymm0, 0x39 vpshufd ymm3, ymm3, 0x4E vpshufd ymm2, ymm2, 0x93 dec al jz 9f vshufps ymm8, ymm4, ymm5, 214 vpshufd ymm9, ymm4, 0x0F vpshufd ymm4, ymm8, 0x39 vshufps ymm8, ymm6, ymm7, 250 vpblendd ymm9, ymm9, ymm8, 0xAA vpunpcklqdq ymm8, ymm7, ymm5 vpblendd ymm8, ymm8, ymm6, 0x88 vpshufd ymm8, ymm8, 0x78 vpunpckhdq ymm5, ymm5, ymm7 vpunpckldq ymm6, ymm6, ymm5 vpshufd ymm7, ymm6, 0x1E vmovdqa ymm5, ymm9 vmovdqa ymm6, ymm8 jmp 9b 9: vpxor ymm0, ymm0, ymm2 vpxor ymm1, ymm1, ymm3 mov eax, r13d cmp rdx, r15 jne 2b vmovdqu xmmword ptr [rbx], xmm0 vmovdqu xmmword ptr [rbx+0x10], xmm1 vextracti128 xmmword ptr [rbx+0x20], ymm0, 0x01 vextracti128 xmmword ptr [rbx+0x30], ymm1, 0x01 vmovaps ymm8, ymmword ptr [rsp+0x280] vmovaps ymm0, ymmword ptr [rsp+0x240] vmovups ymm1, ymmword ptr [rsp+0x248] vmovaps ymm2, ymmword ptr [rsp+0x260] vmovups ymm3, ymmword ptr [rsp+0x268] vblendvps ymm0, ymm0, ymm1, ymm8 vblendvps ymm2, ymm2, ymm3, ymm8 vmovaps ymmword ptr [rsp+0x240], ymm0 vmovaps ymmword ptr [rsp+0x260], ymm2 add rbx, 64 add rdi, 16 sub rsi, 2 3: test rsi, 0x1 je 4b vmovdqu xmm0, xmmword ptr [rcx] vmovdqu xmm1, xmmword ptr [rcx+0x10] vmovd xmm3, dword ptr [rsp+0x240] vpinsrd xmm3, xmm3, dword ptr [rsp+0x260], 1 vpinsrd xmm13, xmm3, dword ptr [BLAKE3_BLOCK_LEN+rip], 2 vmovdqa xmm14, xmmword ptr [ROT16+rip] vmovdqa xmm15, xmmword ptr [ROT8+rip] mov r8, qword ptr [rdi] movzx eax, byte ptr [rbp+0x40] or eax, r13d xor edx, edx .p2align 5 2: mov r14d, eax or eax, r12d add rdx, 64 cmp rdx, r15 cmovne eax, r14d vmovdqa xmm2, xmmword ptr [BLAKE3_IV+rip] vmovdqa xmm3, xmm13 vpinsrd xmm3, xmm3, eax, 3 vmovups xmm8, xmmword ptr [r8+rdx-0x40] vmovups xmm9, xmmword ptr [r8+rdx-0x30] vshufps xmm4, xmm8, xmm9, 136 vshufps xmm5, xmm8, xmm9, 221 vmovups xmm8, xmmword ptr [r8+rdx-0x20] vmovups xmm9, xmmword ptr [r8+rdx-0x10] vshufps xmm6, xmm8, xmm9, 136 vshufps xmm7, xmm8, xmm9, 221 vpshufd xmm6, xmm6, 0x93 vpshufd xmm7, xmm7, 0x93 mov al, 7 9: vpaddd xmm0, xmm0, xmm4 vpaddd xmm0, xmm0, xmm1 vpxor xmm3, xmm3, xmm0 vpshufb xmm3, xmm3, xmm14 vpaddd xmm2, xmm2, xmm3 vpxor xmm1, xmm1, xmm2 vpsrld xmm8, xmm1, 12 vpslld xmm1, xmm1, 20 vpor xmm1, xmm1, xmm8 vpaddd xmm0, xmm0, xmm5 vpaddd xmm0, xmm0, xmm1 vpxor xmm3, xmm3, xmm0 vpshufb xmm3, xmm3, xmm15 vpaddd xmm2, xmm2, xmm3 vpxor xmm1, xmm1, xmm2 vpsrld xmm8, xmm1, 7 vpslld xmm1, xmm1, 25 vpor xmm1, xmm1, xmm8 vpshufd xmm0, xmm0, 0x93 vpshufd xmm3, xmm3, 0x4E vpshufd xmm2, xmm2, 0x39 vpaddd xmm0, xmm0, xmm6 vpaddd xmm0, xmm0, xmm1 vpxor xmm3, xmm3, xmm0 vpshufb xmm3, xmm3, xmm14 vpaddd xmm2, xmm2, xmm3 vpxor xmm1, xmm1, xmm2 vpsrld xmm8, xmm1, 12 vpslld xmm1, xmm1, 20 vpor xmm1, xmm1, xmm8 vpaddd xmm0, xmm0, xmm7 vpaddd xmm0, xmm0, xmm1 vpxor xmm3, xmm3, xmm0 vpshufb xmm3, xmm3, xmm15 vpaddd xmm2, xmm2, xmm3 vpxor xmm1, xmm1, xmm2 vpsrld xmm8, xmm1, 7 vpslld xmm1, xmm1, 25 vpor xmm1, xmm1, xmm8 vpshufd xmm0, xmm0, 0x39 vpshufd xmm3, xmm3, 0x4E vpshufd xmm2, xmm2, 0x93 dec al jz 9f vshufps xmm8, xmm4, xmm5, 214 vpshufd xmm9, xmm4, 0x0F vpshufd xmm4, xmm8, 0x39 vshufps xmm8, xmm6, xmm7, 250 vpblendd xmm9, xmm9, xmm8, 0xAA vpunpcklqdq xmm8, xmm7, xmm5 vpblendd xmm8, xmm8, xmm6, 0x88 vpshufd xmm8, xmm8, 0x78 vpunpckhdq xmm5, xmm5, xmm7 vpunpckldq xmm6, xmm6, xmm5 vpshufd xmm7, xmm6, 0x1E vmovdqa xmm5, xmm9 vmovdqa xmm6, xmm8 jmp 9b 9: vpxor xmm0, xmm0, xmm2 vpxor xmm1, xmm1, xmm3 mov eax, r13d cmp rdx, r15 jne 2b vmovdqu xmmword ptr [rbx], xmm0 vmovdqu xmmword ptr [rbx+0x10], xmm1 jmp 4b #ifdef __APPLE__ .static_data #else .section .rodata #endif .p2align 6 ADD0: .long 0, 1, 2, 3, 4, 5, 6, 7 ADD1: .long 8, 8, 8, 8, 8, 8, 8, 8 BLAKE3_IV_0: .long 0x6A09E667, 0x6A09E667, 0x6A09E667, 0x6A09E667 .long 0x6A09E667, 0x6A09E667, 0x6A09E667, 0x6A09E667 BLAKE3_IV_1: .long 0xBB67AE85, 0xBB67AE85, 0xBB67AE85, 0xBB67AE85 .long 0xBB67AE85, 0xBB67AE85, 0xBB67AE85, 0xBB67AE85 BLAKE3_IV_2: .long 0x3C6EF372, 0x3C6EF372, 0x3C6EF372, 0x3C6EF372 .long 0x3C6EF372, 0x3C6EF372, 0x3C6EF372, 0x3C6EF372 BLAKE3_IV_3: .long 0xA54FF53A, 0xA54FF53A, 0xA54FF53A, 0xA54FF53A .long 0xA54FF53A, 0xA54FF53A, 0xA54FF53A, 0xA54FF53A BLAKE3_BLOCK_LEN: .long 0x00000040, 0x00000040, 0x00000040, 0x00000040 .long 0x00000040, 0x00000040, 0x00000040, 0x00000040 ROT16: .byte 2, 3, 0, 1, 6, 7, 4, 5, 10, 11, 8, 9, 14, 15, 12, 13 ROT8: .byte 1, 2, 3, 0, 5, 6, 7, 4, 9, 10, 11, 8, 13, 14, 15, 12 CMP_MSB_MASK: .long 0x80000000, 0x80000000, 0x80000000, 0x80000000 .long 0x80000000, 0x80000000, 0x80000000, 0x80000000 BLAKE3_IV: .long 0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A librecast/libs/blake3/c/blake3_avx2_x86-64_windows_gnu.S000066400000000000000000002022571502456746400231730ustar00rootroot00000000000000.intel_syntax noprefix .global _blake3_hash_many_avx2 .global blake3_hash_many_avx2 .section .text .p2align 6 _blake3_hash_many_avx2: blake3_hash_many_avx2: push r15 push r14 push r13 push r12 push rsi push rdi push rbx push rbp mov rbp, rsp sub rsp, 880 and rsp, 0xFFFFFFFFFFFFFFC0 vmovdqa xmmword ptr [rsp+0x2D0], xmm6 vmovdqa xmmword ptr [rsp+0x2E0], xmm7 vmovdqa xmmword ptr [rsp+0x2F0], xmm8 vmovdqa xmmword ptr [rsp+0x300], xmm9 vmovdqa xmmword ptr [rsp+0x310], xmm10 vmovdqa xmmword ptr [rsp+0x320], xmm11 vmovdqa xmmword ptr [rsp+0x330], xmm12 vmovdqa xmmword ptr [rsp+0x340], xmm13 vmovdqa xmmword ptr [rsp+0x350], xmm14 vmovdqa xmmword ptr [rsp+0x360], xmm15 mov rdi, rcx mov rsi, rdx mov rdx, r8 mov rcx, r9 mov r8, qword ptr [rbp+0x68] movzx r9, byte ptr [rbp+0x70] neg r9d vmovd xmm0, r9d vpbroadcastd ymm0, xmm0 vmovdqa ymmword ptr [rsp+0x260], ymm0 vpand ymm1, ymm0, ymmword ptr [ADD0+rip] vpand ymm2, ymm0, ymmword ptr [ADD1+rip] vmovdqa ymmword ptr [rsp+0x2A0], ymm2 vmovd xmm2, r8d vpbroadcastd ymm2, xmm2 vpaddd ymm2, ymm2, ymm1 vmovdqa ymmword ptr [rsp+0x220], ymm2 vpxor ymm1, ymm1, ymmword ptr [CMP_MSB_MASK+rip] vpxor ymm2, ymm2, ymmword ptr [CMP_MSB_MASK+rip] vpcmpgtd ymm2, ymm1, ymm2 shr r8, 32 vmovd xmm3, r8d vpbroadcastd ymm3, xmm3 vpsubd ymm3, ymm3, ymm2 vmovdqa ymmword ptr [rsp+0x240], ymm3 shl rdx, 6 mov qword ptr [rsp+0x2C0], rdx cmp rsi, 8 jc 3f 2: vpbroadcastd ymm0, dword ptr [rcx] vpbroadcastd ymm1, dword ptr [rcx+0x4] vpbroadcastd ymm2, dword ptr [rcx+0x8] vpbroadcastd ymm3, dword ptr [rcx+0xC] vpbroadcastd ymm4, dword ptr [rcx+0x10] vpbroadcastd ymm5, dword ptr [rcx+0x14] vpbroadcastd ymm6, dword ptr [rcx+0x18] vpbroadcastd ymm7, dword ptr [rcx+0x1C] mov r8, qword ptr [rdi] mov r9, qword ptr [rdi+0x8] mov r10, qword ptr [rdi+0x10] mov r11, qword ptr [rdi+0x18] mov r12, qword ptr [rdi+0x20] mov r13, qword ptr [rdi+0x28] mov r14, qword ptr [rdi+0x30] mov r15, qword ptr [rdi+0x38] movzx eax, byte ptr [rbp+0x78] movzx ebx, byte ptr [rbp+0x80] or eax, ebx xor edx, edx .p2align 5 9: movzx ebx, byte ptr [rbp+0x88] or ebx, eax add rdx, 64 cmp rdx, qword ptr [rsp+0x2C0] cmove eax, ebx mov dword ptr [rsp+0x200], eax vmovups xmm8, xmmword ptr [r8+rdx-0x40] vinsertf128 ymm8, ymm8, xmmword ptr [r12+rdx-0x40], 0x01 vmovups xmm9, xmmword ptr [r9+rdx-0x40] vinsertf128 ymm9, ymm9, xmmword ptr [r13+rdx-0x40], 0x01 vunpcklpd ymm12, ymm8, ymm9 vunpckhpd ymm13, ymm8, ymm9 vmovups xmm10, xmmword ptr [r10+rdx-0x40] vinsertf128 ymm10, ymm10, xmmword ptr [r14+rdx-0x40], 0x01 vmovups xmm11, xmmword ptr [r11+rdx-0x40] vinsertf128 ymm11, ymm11, xmmword ptr [r15+rdx-0x40], 0x01 vunpcklpd ymm14, ymm10, ymm11 vunpckhpd ymm15, ymm10, ymm11 vshufps ymm8, ymm12, ymm14, 136 vmovaps ymmword ptr [rsp], ymm8 vshufps ymm9, ymm12, ymm14, 221 vmovaps ymmword ptr [rsp+0x20], ymm9 vshufps ymm10, ymm13, ymm15, 136 vmovaps ymmword ptr [rsp+0x40], ymm10 vshufps ymm11, ymm13, ymm15, 221 vmovaps ymmword ptr [rsp+0x60], ymm11 vmovups xmm8, xmmword ptr [r8+rdx-0x30] vinsertf128 ymm8, ymm8, xmmword ptr [r12+rdx-0x30], 0x01 vmovups xmm9, xmmword ptr [r9+rdx-0x30] vinsertf128 ymm9, ymm9, xmmword ptr [r13+rdx-0x30], 0x01 vunpcklpd ymm12, ymm8, ymm9 vunpckhpd ymm13, ymm8, ymm9 vmovups xmm10, xmmword ptr [r10+rdx-0x30] vinsertf128 ymm10, ymm10, xmmword ptr [r14+rdx-0x30], 0x01 vmovups xmm11, xmmword ptr [r11+rdx-0x30] vinsertf128 ymm11, ymm11, xmmword ptr [r15+rdx-0x30], 0x01 vunpcklpd ymm14, ymm10, ymm11 vunpckhpd ymm15, ymm10, ymm11 vshufps ymm8, ymm12, ymm14, 136 vmovaps ymmword ptr [rsp+0x80], ymm8 vshufps ymm9, ymm12, ymm14, 221 vmovaps ymmword ptr [rsp+0xA0], ymm9 vshufps ymm10, ymm13, ymm15, 136 vmovaps ymmword ptr [rsp+0xC0], ymm10 vshufps ymm11, ymm13, ymm15, 221 vmovaps ymmword ptr [rsp+0xE0], ymm11 vmovups xmm8, xmmword ptr [r8+rdx-0x20] vinsertf128 ymm8, ymm8, xmmword ptr [r12+rdx-0x20], 0x01 vmovups xmm9, xmmword ptr [r9+rdx-0x20] vinsertf128 ymm9, ymm9, xmmword ptr [r13+rdx-0x20], 0x01 vunpcklpd ymm12, ymm8, ymm9 vunpckhpd ymm13, ymm8, ymm9 vmovups xmm10, xmmword ptr [r10+rdx-0x20] vinsertf128 ymm10, ymm10, xmmword ptr [r14+rdx-0x20], 0x01 vmovups xmm11, xmmword ptr [r11+rdx-0x20] vinsertf128 ymm11, ymm11, xmmword ptr [r15+rdx-0x20], 0x01 vunpcklpd ymm14, ymm10, ymm11 vunpckhpd ymm15, ymm10, ymm11 vshufps ymm8, ymm12, ymm14, 136 vmovaps ymmword ptr [rsp+0x100], ymm8 vshufps ymm9, ymm12, ymm14, 221 vmovaps ymmword ptr [rsp+0x120], ymm9 vshufps ymm10, ymm13, ymm15, 136 vmovaps ymmword ptr [rsp+0x140], ymm10 vshufps ymm11, ymm13, ymm15, 221 vmovaps ymmword ptr [rsp+0x160], ymm11 vmovups xmm8, xmmword ptr [r8+rdx-0x10] vinsertf128 ymm8, ymm8, xmmword ptr [r12+rdx-0x10], 0x01 vmovups xmm9, xmmword ptr [r9+rdx-0x10] vinsertf128 ymm9, ymm9, xmmword ptr [r13+rdx-0x10], 0x01 vunpcklpd ymm12, ymm8, ymm9 vunpckhpd ymm13, ymm8, ymm9 vmovups xmm10, xmmword ptr [r10+rdx-0x10] vinsertf128 ymm10, ymm10, xmmword ptr [r14+rdx-0x10], 0x01 vmovups xmm11, xmmword ptr [r11+rdx-0x10] vinsertf128 ymm11, ymm11, xmmword ptr [r15+rdx-0x10], 0x01 vunpcklpd ymm14, ymm10, ymm11 vunpckhpd ymm15, ymm10, ymm11 vshufps ymm8, ymm12, ymm14, 136 vmovaps ymmword ptr [rsp+0x180], ymm8 vshufps ymm9, ymm12, ymm14, 221 vmovaps ymmword ptr [rsp+0x1A0], ymm9 vshufps ymm10, ymm13, ymm15, 136 vmovaps ymmword ptr [rsp+0x1C0], ymm10 vshufps ymm11, ymm13, ymm15, 221 vmovaps ymmword ptr [rsp+0x1E0], ymm11 vpbroadcastd ymm15, dword ptr [rsp+0x200] prefetcht0 [r8+rdx+0x80] prefetcht0 [r12+rdx+0x80] prefetcht0 [r9+rdx+0x80] prefetcht0 [r13+rdx+0x80] prefetcht0 [r10+rdx+0x80] prefetcht0 [r14+rdx+0x80] prefetcht0 [r11+rdx+0x80] prefetcht0 [r15+rdx+0x80] vpaddd ymm0, ymm0, ymmword ptr [rsp] vpaddd ymm1, ymm1, ymmword ptr [rsp+0x40] vpaddd ymm2, ymm2, ymmword ptr [rsp+0x80] vpaddd ymm3, ymm3, ymmword ptr [rsp+0xC0] vpaddd ymm0, ymm0, ymm4 vpaddd ymm1, ymm1, ymm5 vpaddd ymm2, ymm2, ymm6 vpaddd ymm3, ymm3, ymm7 vpxor ymm12, ymm0, ymmword ptr [rsp+0x220] vpxor ymm13, ymm1, ymmword ptr [rsp+0x240] vpxor ymm14, ymm2, ymmword ptr [BLAKE3_BLOCK_LEN+rip] vpxor ymm15, ymm3, ymm15 vbroadcasti128 ymm8, xmmword ptr [ROT16+rip] vpshufb ymm12, ymm12, ymm8 vpshufb ymm13, ymm13, ymm8 vpshufb ymm14, ymm14, ymm8 vpshufb ymm15, ymm15, ymm8 vpaddd ymm8, ymm12, ymmword ptr [BLAKE3_IV_0+rip] vpaddd ymm9, ymm13, ymmword ptr [BLAKE3_IV_1+rip] vpaddd ymm10, ymm14, ymmword ptr [BLAKE3_IV_2+rip] vpaddd ymm11, ymm15, ymmword ptr [BLAKE3_IV_3+rip] vpxor ymm4, ymm4, ymm8 vpxor ymm5, ymm5, ymm9 vpxor ymm6, ymm6, ymm10 vpxor ymm7, ymm7, ymm11 vmovdqa ymmword ptr [rsp+0x200], ymm8 vpsrld ymm8, ymm4, 12 vpslld ymm4, ymm4, 20 vpor ymm4, ymm4, ymm8 vpsrld ymm8, ymm5, 12 vpslld ymm5, ymm5, 20 vpor ymm5, ymm5, ymm8 vpsrld ymm8, ymm6, 12 vpslld ymm6, ymm6, 20 vpor ymm6, ymm6, ymm8 vpsrld ymm8, ymm7, 12 vpslld ymm7, ymm7, 20 vpor ymm7, ymm7, ymm8 vpaddd ymm0, ymm0, ymmword ptr [rsp+0x20] vpaddd ymm1, ymm1, ymmword ptr [rsp+0x60] vpaddd ymm2, ymm2, ymmword ptr [rsp+0xA0] vpaddd ymm3, ymm3, ymmword ptr [rsp+0xE0] vpaddd ymm0, ymm0, ymm4 vpaddd ymm1, ymm1, ymm5 vpaddd ymm2, ymm2, ymm6 vpaddd ymm3, ymm3, ymm7 vpxor ymm12, ymm12, ymm0 vpxor ymm13, ymm13, ymm1 vpxor ymm14, ymm14, ymm2 vpxor ymm15, ymm15, ymm3 vbroadcasti128 ymm8, xmmword ptr [ROT8+rip] vpshufb ymm12, ymm12, ymm8 vpshufb ymm13, ymm13, ymm8 vpshufb ymm14, ymm14, ymm8 vpshufb ymm15, ymm15, ymm8 vpaddd ymm8, ymm12, ymmword ptr [rsp+0x200] vpaddd ymm9, ymm9, ymm13 vpaddd ymm10, ymm10, ymm14 vpaddd ymm11, ymm11, ymm15 vpxor ymm4, ymm4, ymm8 vpxor ymm5, ymm5, ymm9 vpxor ymm6, ymm6, ymm10 vpxor ymm7, ymm7, ymm11 vmovdqa ymmword ptr [rsp+0x200], ymm8 vpsrld ymm8, ymm4, 7 vpslld ymm4, ymm4, 25 vpor ymm4, ymm4, ymm8 vpsrld ymm8, ymm5, 7 vpslld ymm5, ymm5, 25 vpor ymm5, ymm5, ymm8 vpsrld ymm8, ymm6, 7 vpslld ymm6, ymm6, 25 vpor ymm6, ymm6, ymm8 vpsrld ymm8, ymm7, 7 vpslld ymm7, ymm7, 25 vpor ymm7, ymm7, ymm8 vpaddd ymm0, ymm0, ymmword ptr [rsp+0x100] vpaddd ymm1, ymm1, ymmword ptr [rsp+0x140] vpaddd ymm2, ymm2, ymmword ptr [rsp+0x180] vpaddd ymm3, ymm3, ymmword ptr [rsp+0x1C0] vpaddd ymm0, ymm0, ymm5 vpaddd ymm1, ymm1, ymm6 vpaddd ymm2, ymm2, ymm7 vpaddd ymm3, ymm3, ymm4 vpxor ymm15, ymm15, ymm0 vpxor ymm12, ymm12, ymm1 vpxor ymm13, ymm13, ymm2 vpxor ymm14, ymm14, ymm3 vbroadcasti128 ymm8, xmmword ptr [ROT16+rip] vpshufb ymm15, ymm15, ymm8 vpshufb ymm12, ymm12, ymm8 vpshufb ymm13, ymm13, ymm8 vpshufb ymm14, ymm14, ymm8 vpaddd ymm10, ymm10, ymm15 vpaddd ymm11, ymm11, ymm12 vpaddd ymm8, ymm13, ymmword ptr [rsp+0x200] vpaddd ymm9, ymm9, ymm14 vpxor ymm5, ymm5, ymm10 vpxor ymm6, ymm6, ymm11 vpxor ymm7, ymm7, ymm8 vpxor ymm4, ymm4, ymm9 vmovdqa ymmword ptr [rsp+0x200], ymm8 vpsrld ymm8, ymm5, 12 vpslld ymm5, ymm5, 20 vpor ymm5, ymm5, ymm8 vpsrld ymm8, ymm6, 12 vpslld ymm6, ymm6, 20 vpor ymm6, ymm6, ymm8 vpsrld ymm8, ymm7, 12 vpslld ymm7, ymm7, 20 vpor ymm7, ymm7, ymm8 vpsrld ymm8, ymm4, 12 vpslld ymm4, ymm4, 20 vpor ymm4, ymm4, ymm8 vpaddd ymm0, ymm0, ymmword ptr [rsp+0x120] vpaddd ymm1, ymm1, ymmword ptr [rsp+0x160] vpaddd ymm2, ymm2, ymmword ptr [rsp+0x1A0] vpaddd ymm3, ymm3, ymmword ptr [rsp+0x1E0] vpaddd ymm0, ymm0, ymm5 vpaddd ymm1, ymm1, ymm6 vpaddd ymm2, ymm2, ymm7 vpaddd ymm3, ymm3, ymm4 vpxor ymm15, ymm15, ymm0 vpxor ymm12, ymm12, ymm1 vpxor ymm13, ymm13, ymm2 vpxor ymm14, ymm14, ymm3 vbroadcasti128 ymm8, xmmword ptr [ROT8+rip] vpshufb ymm15, ymm15, ymm8 vpshufb ymm12, ymm12, ymm8 vpshufb ymm13, ymm13, ymm8 vpshufb ymm14, ymm14, ymm8 vpaddd ymm10, ymm10, ymm15 vpaddd ymm11, ymm11, ymm12 vpaddd ymm8, ymm13, ymmword ptr [rsp+0x200] vpaddd ymm9, ymm9, ymm14 vpxor ymm5, ymm5, ymm10 vpxor ymm6, ymm6, ymm11 vpxor ymm7, ymm7, ymm8 vpxor ymm4, ymm4, ymm9 vmovdqa ymmword ptr [rsp+0x200], ymm8 vpsrld ymm8, ymm5, 7 vpslld ymm5, ymm5, 25 vpor ymm5, ymm5, ymm8 vpsrld ymm8, ymm6, 7 vpslld ymm6, ymm6, 25 vpor ymm6, ymm6, ymm8 vpsrld ymm8, ymm7, 7 vpslld ymm7, ymm7, 25 vpor ymm7, ymm7, ymm8 vpsrld ymm8, ymm4, 7 vpslld ymm4, ymm4, 25 vpor ymm4, ymm4, ymm8 vpaddd ymm0, ymm0, ymmword ptr [rsp+0x40] vpaddd ymm1, ymm1, ymmword ptr [rsp+0x60] vpaddd ymm2, ymm2, ymmword ptr [rsp+0xE0] vpaddd ymm3, ymm3, ymmword ptr [rsp+0x80] vpaddd ymm0, ymm0, ymm4 vpaddd ymm1, ymm1, ymm5 vpaddd ymm2, ymm2, ymm6 vpaddd ymm3, ymm3, ymm7 vpxor ymm12, ymm12, ymm0 vpxor ymm13, ymm13, ymm1 vpxor ymm14, ymm14, ymm2 vpxor ymm15, ymm15, ymm3 vbroadcasti128 ymm8, xmmword ptr [ROT16+rip] vpshufb ymm12, ymm12, ymm8 vpshufb ymm13, ymm13, ymm8 vpshufb ymm14, ymm14, ymm8 vpshufb ymm15, ymm15, ymm8 vpaddd ymm8, ymm12, ymmword ptr [rsp+0x200] vpaddd ymm9, ymm9, ymm13 vpaddd ymm10, ymm10, ymm14 vpaddd ymm11, ymm11, ymm15 vpxor ymm4, ymm4, ymm8 vpxor ymm5, ymm5, ymm9 vpxor ymm6, ymm6, ymm10 vpxor ymm7, ymm7, ymm11 vmovdqa ymmword ptr [rsp+0x200], ymm8 vpsrld ymm8, ymm4, 12 vpslld ymm4, ymm4, 20 vpor ymm4, ymm4, ymm8 vpsrld ymm8, ymm5, 12 vpslld ymm5, ymm5, 20 vpor ymm5, ymm5, ymm8 vpsrld ymm8, ymm6, 12 vpslld ymm6, ymm6, 20 vpor ymm6, ymm6, ymm8 vpsrld ymm8, ymm7, 12 vpslld ymm7, ymm7, 20 vpor ymm7, ymm7, ymm8 vpaddd ymm0, ymm0, ymmword ptr [rsp+0xC0] vpaddd ymm1, ymm1, ymmword ptr [rsp+0x140] vpaddd ymm2, ymm2, ymmword ptr [rsp] vpaddd ymm3, ymm3, ymmword ptr [rsp+0x1A0] vpaddd ymm0, ymm0, ymm4 vpaddd ymm1, ymm1, ymm5 vpaddd ymm2, ymm2, ymm6 vpaddd ymm3, ymm3, ymm7 vpxor ymm12, ymm12, ymm0 vpxor ymm13, ymm13, ymm1 vpxor ymm14, ymm14, ymm2 vpxor ymm15, ymm15, ymm3 vbroadcasti128 ymm8, xmmword ptr [ROT8+rip] vpshufb ymm12, ymm12, ymm8 vpshufb ymm13, ymm13, ymm8 vpshufb ymm14, ymm14, ymm8 vpshufb ymm15, ymm15, ymm8 vpaddd ymm8, ymm12, ymmword ptr [rsp+0x200] vpaddd ymm9, ymm9, ymm13 vpaddd ymm10, ymm10, ymm14 vpaddd ymm11, ymm11, ymm15 vpxor ymm4, ymm4, ymm8 vpxor ymm5, ymm5, ymm9 vpxor ymm6, ymm6, ymm10 vpxor ymm7, ymm7, ymm11 vmovdqa ymmword ptr [rsp+0x200], ymm8 vpsrld ymm8, ymm4, 7 vpslld ymm4, ymm4, 25 vpor ymm4, ymm4, ymm8 vpsrld ymm8, ymm5, 7 vpslld ymm5, ymm5, 25 vpor ymm5, ymm5, ymm8 vpsrld ymm8, ymm6, 7 vpslld ymm6, ymm6, 25 vpor ymm6, ymm6, ymm8 vpsrld ymm8, ymm7, 7 vpslld ymm7, ymm7, 25 vpor ymm7, ymm7, ymm8 vpaddd ymm0, ymm0, ymmword ptr [rsp+0x20] vpaddd ymm1, ymm1, ymmword ptr [rsp+0x180] vpaddd ymm2, ymm2, ymmword ptr [rsp+0x120] vpaddd ymm3, ymm3, ymmword ptr [rsp+0x1E0] vpaddd ymm0, ymm0, ymm5 vpaddd ymm1, ymm1, ymm6 vpaddd ymm2, ymm2, ymm7 vpaddd ymm3, ymm3, ymm4 vpxor ymm15, ymm15, ymm0 vpxor ymm12, ymm12, ymm1 vpxor ymm13, ymm13, ymm2 vpxor ymm14, ymm14, ymm3 vbroadcasti128 ymm8, xmmword ptr [ROT16+rip] vpshufb ymm15, ymm15, ymm8 vpshufb ymm12, ymm12, ymm8 vpshufb ymm13, ymm13, ymm8 vpshufb ymm14, ymm14, ymm8 vpaddd ymm10, ymm10, ymm15 vpaddd ymm11, ymm11, ymm12 vpaddd ymm8, ymm13, ymmword ptr [rsp+0x200] vpaddd ymm9, ymm9, ymm14 vpxor ymm5, ymm5, ymm10 vpxor ymm6, ymm6, ymm11 vpxor ymm7, ymm7, ymm8 vpxor ymm4, ymm4, ymm9 vmovdqa ymmword ptr [rsp+0x200], ymm8 vpsrld ymm8, ymm5, 12 vpslld ymm5, ymm5, 20 vpor ymm5, ymm5, ymm8 vpsrld ymm8, ymm6, 12 vpslld ymm6, ymm6, 20 vpor ymm6, ymm6, ymm8 vpsrld ymm8, ymm7, 12 vpslld ymm7, ymm7, 20 vpor ymm7, ymm7, ymm8 vpsrld ymm8, ymm4, 12 vpslld ymm4, ymm4, 20 vpor ymm4, ymm4, ymm8 vpaddd ymm0, ymm0, ymmword ptr [rsp+0x160] vpaddd ymm1, ymm1, ymmword ptr [rsp+0xA0] vpaddd ymm2, ymm2, ymmword ptr [rsp+0x1C0] vpaddd ymm3, ymm3, ymmword ptr [rsp+0x100] vpaddd ymm0, ymm0, ymm5 vpaddd ymm1, ymm1, ymm6 vpaddd ymm2, ymm2, ymm7 vpaddd ymm3, ymm3, ymm4 vpxor ymm15, ymm15, ymm0 vpxor ymm12, ymm12, ymm1 vpxor ymm13, ymm13, ymm2 vpxor ymm14, ymm14, ymm3 vbroadcasti128 ymm8, xmmword ptr [ROT8+rip] vpshufb ymm15, ymm15, ymm8 vpshufb ymm12, ymm12, ymm8 vpshufb ymm13, ymm13, ymm8 vpshufb ymm14, ymm14, ymm8 vpaddd ymm10, ymm10, ymm15 vpaddd ymm11, ymm11, ymm12 vpaddd ymm8, ymm13, ymmword ptr [rsp+0x200] vpaddd ymm9, ymm9, ymm14 vpxor ymm5, ymm5, ymm10 vpxor ymm6, ymm6, ymm11 vpxor ymm7, ymm7, ymm8 vpxor ymm4, ymm4, ymm9 vmovdqa ymmword ptr [rsp+0x200], ymm8 vpsrld ymm8, ymm5, 7 vpslld ymm5, ymm5, 25 vpor ymm5, ymm5, ymm8 vpsrld ymm8, ymm6, 7 vpslld ymm6, ymm6, 25 vpor ymm6, ymm6, ymm8 vpsrld ymm8, ymm7, 7 vpslld ymm7, ymm7, 25 vpor ymm7, ymm7, ymm8 vpsrld ymm8, ymm4, 7 vpslld ymm4, ymm4, 25 vpor ymm4, ymm4, ymm8 vpaddd ymm0, ymm0, ymmword ptr [rsp+0x60] vpaddd ymm1, ymm1, ymmword ptr [rsp+0x140] vpaddd ymm2, ymm2, ymmword ptr [rsp+0x1A0] vpaddd ymm3, ymm3, ymmword ptr [rsp+0xE0] vpaddd ymm0, ymm0, ymm4 vpaddd ymm1, ymm1, ymm5 vpaddd ymm2, ymm2, ymm6 vpaddd ymm3, ymm3, ymm7 vpxor ymm12, ymm12, ymm0 vpxor ymm13, ymm13, ymm1 vpxor ymm14, ymm14, ymm2 vpxor ymm15, ymm15, ymm3 vbroadcasti128 ymm8, xmmword ptr [ROT16+rip] vpshufb ymm12, ymm12, ymm8 vpshufb ymm13, ymm13, ymm8 vpshufb ymm14, ymm14, ymm8 vpshufb ymm15, ymm15, ymm8 vpaddd ymm8, ymm12, ymmword ptr [rsp+0x200] vpaddd ymm9, ymm9, ymm13 vpaddd ymm10, ymm10, ymm14 vpaddd ymm11, ymm11, ymm15 vpxor ymm4, ymm4, ymm8 vpxor ymm5, ymm5, ymm9 vpxor ymm6, ymm6, ymm10 vpxor ymm7, ymm7, ymm11 vmovdqa ymmword ptr [rsp+0x200], ymm8 vpsrld ymm8, ymm4, 12 vpslld ymm4, ymm4, 20 vpor ymm4, ymm4, ymm8 vpsrld ymm8, ymm5, 12 vpslld ymm5, ymm5, 20 vpor ymm5, ymm5, ymm8 vpsrld ymm8, ymm6, 12 vpslld ymm6, ymm6, 20 vpor ymm6, ymm6, ymm8 vpsrld ymm8, ymm7, 12 vpslld ymm7, ymm7, 20 vpor ymm7, ymm7, ymm8 vpaddd ymm0, ymm0, ymmword ptr [rsp+0x80] vpaddd ymm1, ymm1, ymmword ptr [rsp+0x180] vpaddd ymm2, ymm2, ymmword ptr [rsp+0x40] vpaddd ymm3, ymm3, ymmword ptr [rsp+0x1C0] vpaddd ymm0, ymm0, ymm4 vpaddd ymm1, ymm1, ymm5 vpaddd ymm2, ymm2, ymm6 vpaddd ymm3, ymm3, ymm7 vpxor ymm12, ymm12, ymm0 vpxor ymm13, ymm13, ymm1 vpxor ymm14, ymm14, ymm2 vpxor ymm15, ymm15, ymm3 vbroadcasti128 ymm8, xmmword ptr [ROT8+rip] vpshufb ymm12, ymm12, ymm8 vpshufb ymm13, ymm13, ymm8 vpshufb ymm14, ymm14, ymm8 vpshufb ymm15, ymm15, ymm8 vpaddd ymm8, ymm12, ymmword ptr [rsp+0x200] vpaddd ymm9, ymm9, ymm13 vpaddd ymm10, ymm10, ymm14 vpaddd ymm11, ymm11, ymm15 vpxor ymm4, ymm4, ymm8 vpxor ymm5, ymm5, ymm9 vpxor ymm6, ymm6, ymm10 vpxor ymm7, ymm7, ymm11 vmovdqa ymmword ptr [rsp+0x200], ymm8 vpsrld ymm8, ymm4, 7 vpslld ymm4, ymm4, 25 vpor ymm4, ymm4, ymm8 vpsrld ymm8, ymm5, 7 vpslld ymm5, ymm5, 25 vpor ymm5, ymm5, ymm8 vpsrld ymm8, ymm6, 7 vpslld ymm6, ymm6, 25 vpor ymm6, ymm6, ymm8 vpsrld ymm8, ymm7, 7 vpslld ymm7, ymm7, 25 vpor ymm7, ymm7, ymm8 vpaddd ymm0, ymm0, ymmword ptr [rsp+0xC0] vpaddd ymm1, ymm1, ymmword ptr [rsp+0x120] vpaddd ymm2, ymm2, ymmword ptr [rsp+0x160] vpaddd ymm3, ymm3, ymmword ptr [rsp+0x100] vpaddd ymm0, ymm0, ymm5 vpaddd ymm1, ymm1, ymm6 vpaddd ymm2, ymm2, ymm7 vpaddd ymm3, ymm3, ymm4 vpxor ymm15, ymm15, ymm0 vpxor ymm12, ymm12, ymm1 vpxor ymm13, ymm13, ymm2 vpxor ymm14, ymm14, ymm3 vbroadcasti128 ymm8, xmmword ptr [ROT16+rip] vpshufb ymm15, ymm15, ymm8 vpshufb ymm12, ymm12, ymm8 vpshufb ymm13, ymm13, ymm8 vpshufb ymm14, ymm14, ymm8 vpaddd ymm10, ymm10, ymm15 vpaddd ymm11, ymm11, ymm12 vpaddd ymm8, ymm13, ymmword ptr [rsp+0x200] vpaddd ymm9, ymm9, ymm14 vpxor ymm5, ymm5, ymm10 vpxor ymm6, ymm6, ymm11 vpxor ymm7, ymm7, ymm8 vpxor ymm4, ymm4, ymm9 vmovdqa ymmword ptr [rsp+0x200], ymm8 vpsrld ymm8, ymm5, 12 vpslld ymm5, ymm5, 20 vpor ymm5, ymm5, ymm8 vpsrld ymm8, ymm6, 12 vpslld ymm6, ymm6, 20 vpor ymm6, ymm6, ymm8 vpsrld ymm8, ymm7, 12 vpslld ymm7, ymm7, 20 vpor ymm7, ymm7, ymm8 vpsrld ymm8, ymm4, 12 vpslld ymm4, ymm4, 20 vpor ymm4, ymm4, ymm8 vpaddd ymm0, ymm0, ymmword ptr [rsp+0xA0] vpaddd ymm1, ymm1, ymmword ptr [rsp] vpaddd ymm2, ymm2, ymmword ptr [rsp+0x1E0] vpaddd ymm3, ymm3, ymmword ptr [rsp+0x20] vpaddd ymm0, ymm0, ymm5 vpaddd ymm1, ymm1, ymm6 vpaddd ymm2, ymm2, ymm7 vpaddd ymm3, ymm3, ymm4 vpxor ymm15, ymm15, ymm0 vpxor ymm12, ymm12, ymm1 vpxor ymm13, ymm13, ymm2 vpxor ymm14, ymm14, ymm3 vbroadcasti128 ymm8, xmmword ptr [ROT8+rip] vpshufb ymm15, ymm15, ymm8 vpshufb ymm12, ymm12, ymm8 vpshufb ymm13, ymm13, ymm8 vpshufb ymm14, ymm14, ymm8 vpaddd ymm10, ymm10, ymm15 vpaddd ymm11, ymm11, ymm12 vpaddd ymm8, ymm13, ymmword ptr [rsp+0x200] vpaddd ymm9, ymm9, ymm14 vpxor ymm5, ymm5, ymm10 vpxor ymm6, ymm6, ymm11 vpxor ymm7, ymm7, ymm8 vpxor ymm4, ymm4, ymm9 vmovdqa ymmword ptr [rsp+0x200], ymm8 vpsrld ymm8, ymm5, 7 vpslld ymm5, ymm5, 25 vpor ymm5, ymm5, ymm8 vpsrld ymm8, ymm6, 7 vpslld ymm6, ymm6, 25 vpor ymm6, ymm6, ymm8 vpsrld ymm8, ymm7, 7 vpslld ymm7, ymm7, 25 vpor ymm7, ymm7, ymm8 vpsrld ymm8, ymm4, 7 vpslld ymm4, ymm4, 25 vpor ymm4, ymm4, ymm8 vpaddd ymm0, ymm0, ymmword ptr [rsp+0x140] vpaddd ymm1, ymm1, ymmword ptr [rsp+0x180] vpaddd ymm2, ymm2, ymmword ptr [rsp+0x1C0] vpaddd ymm3, ymm3, ymmword ptr [rsp+0x1A0] vpaddd ymm0, ymm0, ymm4 vpaddd ymm1, ymm1, ymm5 vpaddd ymm2, ymm2, ymm6 vpaddd ymm3, ymm3, ymm7 vpxor ymm12, ymm12, ymm0 vpxor ymm13, ymm13, ymm1 vpxor ymm14, ymm14, ymm2 vpxor ymm15, ymm15, ymm3 vbroadcasti128 ymm8, xmmword ptr [ROT16+rip] vpshufb ymm12, ymm12, ymm8 vpshufb ymm13, ymm13, ymm8 vpshufb ymm14, ymm14, ymm8 vpshufb ymm15, ymm15, ymm8 vpaddd ymm8, ymm12, ymmword ptr [rsp+0x200] vpaddd ymm9, ymm9, ymm13 vpaddd ymm10, ymm10, ymm14 vpaddd ymm11, ymm11, ymm15 vpxor ymm4, ymm4, ymm8 vpxor ymm5, ymm5, ymm9 vpxor ymm6, ymm6, ymm10 vpxor ymm7, ymm7, ymm11 vmovdqa ymmword ptr [rsp+0x200], ymm8 vpsrld ymm8, ymm4, 12 vpslld ymm4, ymm4, 20 vpor ymm4, ymm4, ymm8 vpsrld ymm8, ymm5, 12 vpslld ymm5, ymm5, 20 vpor ymm5, ymm5, ymm8 vpsrld ymm8, ymm6, 12 vpslld ymm6, ymm6, 20 vpor ymm6, ymm6, ymm8 vpsrld ymm8, ymm7, 12 vpslld ymm7, ymm7, 20 vpor ymm7, ymm7, ymm8 vpaddd ymm0, ymm0, ymmword ptr [rsp+0xE0] vpaddd ymm1, ymm1, ymmword ptr [rsp+0x120] vpaddd ymm2, ymm2, ymmword ptr [rsp+0x60] vpaddd ymm3, ymm3, ymmword ptr [rsp+0x1E0] vpaddd ymm0, ymm0, ymm4 vpaddd ymm1, ymm1, ymm5 vpaddd ymm2, ymm2, ymm6 vpaddd ymm3, ymm3, ymm7 vpxor ymm12, ymm12, ymm0 vpxor ymm13, ymm13, ymm1 vpxor ymm14, ymm14, ymm2 vpxor ymm15, ymm15, ymm3 vbroadcasti128 ymm8, xmmword ptr [ROT8+rip] vpshufb ymm12, ymm12, ymm8 vpshufb ymm13, ymm13, ymm8 vpshufb ymm14, ymm14, ymm8 vpshufb ymm15, ymm15, ymm8 vpaddd ymm8, ymm12, ymmword ptr [rsp+0x200] vpaddd ymm9, ymm9, ymm13 vpaddd ymm10, ymm10, ymm14 vpaddd ymm11, ymm11, ymm15 vpxor ymm4, ymm4, ymm8 vpxor ymm5, ymm5, ymm9 vpxor ymm6, ymm6, ymm10 vpxor ymm7, ymm7, ymm11 vmovdqa ymmword ptr [rsp+0x200], ymm8 vpsrld ymm8, ymm4, 7 vpslld ymm4, ymm4, 25 vpor ymm4, ymm4, ymm8 vpsrld ymm8, ymm5, 7 vpslld ymm5, ymm5, 25 vpor ymm5, ymm5, ymm8 vpsrld ymm8, ymm6, 7 vpslld ymm6, ymm6, 25 vpor ymm6, ymm6, ymm8 vpsrld ymm8, ymm7, 7 vpslld ymm7, ymm7, 25 vpor ymm7, ymm7, ymm8 vpaddd ymm0, ymm0, ymmword ptr [rsp+0x80] vpaddd ymm1, ymm1, ymmword ptr [rsp+0x160] vpaddd ymm2, ymm2, ymmword ptr [rsp+0xA0] vpaddd ymm3, ymm3, ymmword ptr [rsp+0x20] vpaddd ymm0, ymm0, ymm5 vpaddd ymm1, ymm1, ymm6 vpaddd ymm2, ymm2, ymm7 vpaddd ymm3, ymm3, ymm4 vpxor ymm15, ymm15, ymm0 vpxor ymm12, ymm12, ymm1 vpxor ymm13, ymm13, ymm2 vpxor ymm14, ymm14, ymm3 vbroadcasti128 ymm8, xmmword ptr [ROT16+rip] vpshufb ymm15, ymm15, ymm8 vpshufb ymm12, ymm12, ymm8 vpshufb ymm13, ymm13, ymm8 vpshufb ymm14, ymm14, ymm8 vpaddd ymm10, ymm10, ymm15 vpaddd ymm11, ymm11, ymm12 vpaddd ymm8, ymm13, ymmword ptr [rsp+0x200] vpaddd ymm9, ymm9, ymm14 vpxor ymm5, ymm5, ymm10 vpxor ymm6, ymm6, ymm11 vpxor ymm7, ymm7, ymm8 vpxor ymm4, ymm4, ymm9 vmovdqa ymmword ptr [rsp+0x200], ymm8 vpsrld ymm8, ymm5, 12 vpslld ymm5, ymm5, 20 vpor ymm5, ymm5, ymm8 vpsrld ymm8, ymm6, 12 vpslld ymm6, ymm6, 20 vpor ymm6, ymm6, ymm8 vpsrld ymm8, ymm7, 12 vpslld ymm7, ymm7, 20 vpor ymm7, ymm7, ymm8 vpsrld ymm8, ymm4, 12 vpslld ymm4, ymm4, 20 vpor ymm4, ymm4, ymm8 vpaddd ymm0, ymm0, ymmword ptr [rsp] vpaddd ymm1, ymm1, ymmword ptr [rsp+0x40] vpaddd ymm2, ymm2, ymmword ptr [rsp+0x100] vpaddd ymm3, ymm3, ymmword ptr [rsp+0xC0] vpaddd ymm0, ymm0, ymm5 vpaddd ymm1, ymm1, ymm6 vpaddd ymm2, ymm2, ymm7 vpaddd ymm3, ymm3, ymm4 vpxor ymm15, ymm15, ymm0 vpxor ymm12, ymm12, ymm1 vpxor ymm13, ymm13, ymm2 vpxor ymm14, ymm14, ymm3 vbroadcasti128 ymm8, xmmword ptr [ROT8+rip] vpshufb ymm15, ymm15, ymm8 vpshufb ymm12, ymm12, ymm8 vpshufb ymm13, ymm13, ymm8 vpshufb ymm14, ymm14, ymm8 vpaddd ymm10, ymm10, ymm15 vpaddd ymm11, ymm11, ymm12 vpaddd ymm8, ymm13, ymmword ptr [rsp+0x200] vpaddd ymm9, ymm9, ymm14 vpxor ymm5, ymm5, ymm10 vpxor ymm6, ymm6, ymm11 vpxor ymm7, ymm7, ymm8 vpxor ymm4, ymm4, ymm9 vmovdqa ymmword ptr [rsp+0x200], ymm8 vpsrld ymm8, ymm5, 7 vpslld ymm5, ymm5, 25 vpor ymm5, ymm5, ymm8 vpsrld ymm8, ymm6, 7 vpslld ymm6, ymm6, 25 vpor ymm6, ymm6, ymm8 vpsrld ymm8, ymm7, 7 vpslld ymm7, ymm7, 25 vpor ymm7, ymm7, ymm8 vpsrld ymm8, ymm4, 7 vpslld ymm4, ymm4, 25 vpor ymm4, ymm4, ymm8 vpaddd ymm0, ymm0, ymmword ptr [rsp+0x180] vpaddd ymm1, ymm1, ymmword ptr [rsp+0x120] vpaddd ymm2, ymm2, ymmword ptr [rsp+0x1E0] vpaddd ymm3, ymm3, ymmword ptr [rsp+0x1C0] vpaddd ymm0, ymm0, ymm4 vpaddd ymm1, ymm1, ymm5 vpaddd ymm2, ymm2, ymm6 vpaddd ymm3, ymm3, ymm7 vpxor ymm12, ymm12, ymm0 vpxor ymm13, ymm13, ymm1 vpxor ymm14, ymm14, ymm2 vpxor ymm15, ymm15, ymm3 vbroadcasti128 ymm8, xmmword ptr [ROT16+rip] vpshufb ymm12, ymm12, ymm8 vpshufb ymm13, ymm13, ymm8 vpshufb ymm14, ymm14, ymm8 vpshufb ymm15, ymm15, ymm8 vpaddd ymm8, ymm12, ymmword ptr [rsp+0x200] vpaddd ymm9, ymm9, ymm13 vpaddd ymm10, ymm10, ymm14 vpaddd ymm11, ymm11, ymm15 vpxor ymm4, ymm4, ymm8 vpxor ymm5, ymm5, ymm9 vpxor ymm6, ymm6, ymm10 vpxor ymm7, ymm7, ymm11 vmovdqa ymmword ptr [rsp+0x200], ymm8 vpsrld ymm8, ymm4, 12 vpslld ymm4, ymm4, 20 vpor ymm4, ymm4, ymm8 vpsrld ymm8, ymm5, 12 vpslld ymm5, ymm5, 20 vpor ymm5, ymm5, ymm8 vpsrld ymm8, ymm6, 12 vpslld ymm6, ymm6, 20 vpor ymm6, ymm6, ymm8 vpsrld ymm8, ymm7, 12 vpslld ymm7, ymm7, 20 vpor ymm7, ymm7, ymm8 vpaddd ymm0, ymm0, ymmword ptr [rsp+0x1A0] vpaddd ymm1, ymm1, ymmword ptr [rsp+0x160] vpaddd ymm2, ymm2, ymmword ptr [rsp+0x140] vpaddd ymm3, ymm3, ymmword ptr [rsp+0x100] vpaddd ymm0, ymm0, ymm4 vpaddd ymm1, ymm1, ymm5 vpaddd ymm2, ymm2, ymm6 vpaddd ymm3, ymm3, ymm7 vpxor ymm12, ymm12, ymm0 vpxor ymm13, ymm13, ymm1 vpxor ymm14, ymm14, ymm2 vpxor ymm15, ymm15, ymm3 vbroadcasti128 ymm8, xmmword ptr [ROT8+rip] vpshufb ymm12, ymm12, ymm8 vpshufb ymm13, ymm13, ymm8 vpshufb ymm14, ymm14, ymm8 vpshufb ymm15, ymm15, ymm8 vpaddd ymm8, ymm12, ymmword ptr [rsp+0x200] vpaddd ymm9, ymm9, ymm13 vpaddd ymm10, ymm10, ymm14 vpaddd ymm11, ymm11, ymm15 vpxor ymm4, ymm4, ymm8 vpxor ymm5, ymm5, ymm9 vpxor ymm6, ymm6, ymm10 vpxor ymm7, ymm7, ymm11 vmovdqa ymmword ptr [rsp+0x200], ymm8 vpsrld ymm8, ymm4, 7 vpslld ymm4, ymm4, 25 vpor ymm4, ymm4, ymm8 vpsrld ymm8, ymm5, 7 vpslld ymm5, ymm5, 25 vpor ymm5, ymm5, ymm8 vpsrld ymm8, ymm6, 7 vpslld ymm6, ymm6, 25 vpor ymm6, ymm6, ymm8 vpsrld ymm8, ymm7, 7 vpslld ymm7, ymm7, 25 vpor ymm7, ymm7, ymm8 vpaddd ymm0, ymm0, ymmword ptr [rsp+0xE0] vpaddd ymm1, ymm1, ymmword ptr [rsp+0xA0] vpaddd ymm2, ymm2, ymmword ptr [rsp] vpaddd ymm3, ymm3, ymmword ptr [rsp+0xC0] vpaddd ymm0, ymm0, ymm5 vpaddd ymm1, ymm1, ymm6 vpaddd ymm2, ymm2, ymm7 vpaddd ymm3, ymm3, ymm4 vpxor ymm15, ymm15, ymm0 vpxor ymm12, ymm12, ymm1 vpxor ymm13, ymm13, ymm2 vpxor ymm14, ymm14, ymm3 vbroadcasti128 ymm8, xmmword ptr [ROT16+rip] vpshufb ymm15, ymm15, ymm8 vpshufb ymm12, ymm12, ymm8 vpshufb ymm13, ymm13, ymm8 vpshufb ymm14, ymm14, ymm8 vpaddd ymm10, ymm10, ymm15 vpaddd ymm11, ymm11, ymm12 vpaddd ymm8, ymm13, ymmword ptr [rsp+0x200] vpaddd ymm9, ymm9, ymm14 vpxor ymm5, ymm5, ymm10 vpxor ymm6, ymm6, ymm11 vpxor ymm7, ymm7, ymm8 vpxor ymm4, ymm4, ymm9 vmovdqa ymmword ptr [rsp+0x200], ymm8 vpsrld ymm8, ymm5, 12 vpslld ymm5, ymm5, 20 vpor ymm5, ymm5, ymm8 vpsrld ymm8, ymm6, 12 vpslld ymm6, ymm6, 20 vpor ymm6, ymm6, ymm8 vpsrld ymm8, ymm7, 12 vpslld ymm7, ymm7, 20 vpor ymm7, ymm7, ymm8 vpsrld ymm8, ymm4, 12 vpslld ymm4, ymm4, 20 vpor ymm4, ymm4, ymm8 vpaddd ymm0, ymm0, ymmword ptr [rsp+0x40] vpaddd ymm1, ymm1, ymmword ptr [rsp+0x60] vpaddd ymm2, ymm2, ymmword ptr [rsp+0x20] vpaddd ymm3, ymm3, ymmword ptr [rsp+0x80] vpaddd ymm0, ymm0, ymm5 vpaddd ymm1, ymm1, ymm6 vpaddd ymm2, ymm2, ymm7 vpaddd ymm3, ymm3, ymm4 vpxor ymm15, ymm15, ymm0 vpxor ymm12, ymm12, ymm1 vpxor ymm13, ymm13, ymm2 vpxor ymm14, ymm14, ymm3 vbroadcasti128 ymm8, xmmword ptr [ROT8+rip] vpshufb ymm15, ymm15, ymm8 vpshufb ymm12, ymm12, ymm8 vpshufb ymm13, ymm13, ymm8 vpshufb ymm14, ymm14, ymm8 vpaddd ymm10, ymm10, ymm15 vpaddd ymm11, ymm11, ymm12 vpaddd ymm8, ymm13, ymmword ptr [rsp+0x200] vpaddd ymm9, ymm9, ymm14 vpxor ymm5, ymm5, ymm10 vpxor ymm6, ymm6, ymm11 vpxor ymm7, ymm7, ymm8 vpxor ymm4, ymm4, ymm9 vmovdqa ymmword ptr [rsp+0x200], ymm8 vpsrld ymm8, ymm5, 7 vpslld ymm5, ymm5, 25 vpor ymm5, ymm5, ymm8 vpsrld ymm8, ymm6, 7 vpslld ymm6, ymm6, 25 vpor ymm6, ymm6, ymm8 vpsrld ymm8, ymm7, 7 vpslld ymm7, ymm7, 25 vpor ymm7, ymm7, ymm8 vpsrld ymm8, ymm4, 7 vpslld ymm4, ymm4, 25 vpor ymm4, ymm4, ymm8 vpaddd ymm0, ymm0, ymmword ptr [rsp+0x120] vpaddd ymm1, ymm1, ymmword ptr [rsp+0x160] vpaddd ymm2, ymm2, ymmword ptr [rsp+0x100] vpaddd ymm3, ymm3, ymmword ptr [rsp+0x1E0] vpaddd ymm0, ymm0, ymm4 vpaddd ymm1, ymm1, ymm5 vpaddd ymm2, ymm2, ymm6 vpaddd ymm3, ymm3, ymm7 vpxor ymm12, ymm12, ymm0 vpxor ymm13, ymm13, ymm1 vpxor ymm14, ymm14, ymm2 vpxor ymm15, ymm15, ymm3 vbroadcasti128 ymm8, xmmword ptr [ROT16+rip] vpshufb ymm12, ymm12, ymm8 vpshufb ymm13, ymm13, ymm8 vpshufb ymm14, ymm14, ymm8 vpshufb ymm15, ymm15, ymm8 vpaddd ymm8, ymm12, ymmword ptr [rsp+0x200] vpaddd ymm9, ymm9, ymm13 vpaddd ymm10, ymm10, ymm14 vpaddd ymm11, ymm11, ymm15 vpxor ymm4, ymm4, ymm8 vpxor ymm5, ymm5, ymm9 vpxor ymm6, ymm6, ymm10 vpxor ymm7, ymm7, ymm11 vmovdqa ymmword ptr [rsp+0x200], ymm8 vpsrld ymm8, ymm4, 12 vpslld ymm4, ymm4, 20 vpor ymm4, ymm4, ymm8 vpsrld ymm8, ymm5, 12 vpslld ymm5, ymm5, 20 vpor ymm5, ymm5, ymm8 vpsrld ymm8, ymm6, 12 vpslld ymm6, ymm6, 20 vpor ymm6, ymm6, ymm8 vpsrld ymm8, ymm7, 12 vpslld ymm7, ymm7, 20 vpor ymm7, ymm7, ymm8 vpaddd ymm0, ymm0, ymmword ptr [rsp+0x1C0] vpaddd ymm1, ymm1, ymmword ptr [rsp+0xA0] vpaddd ymm2, ymm2, ymmword ptr [rsp+0x180] vpaddd ymm3, ymm3, ymmword ptr [rsp+0x20] vpaddd ymm0, ymm0, ymm4 vpaddd ymm1, ymm1, ymm5 vpaddd ymm2, ymm2, ymm6 vpaddd ymm3, ymm3, ymm7 vpxor ymm12, ymm12, ymm0 vpxor ymm13, ymm13, ymm1 vpxor ymm14, ymm14, ymm2 vpxor ymm15, ymm15, ymm3 vbroadcasti128 ymm8, xmmword ptr [ROT8+rip] vpshufb ymm12, ymm12, ymm8 vpshufb ymm13, ymm13, ymm8 vpshufb ymm14, ymm14, ymm8 vpshufb ymm15, ymm15, ymm8 vpaddd ymm8, ymm12, ymmword ptr [rsp+0x200] vpaddd ymm9, ymm9, ymm13 vpaddd ymm10, ymm10, ymm14 vpaddd ymm11, ymm11, ymm15 vpxor ymm4, ymm4, ymm8 vpxor ymm5, ymm5, ymm9 vpxor ymm6, ymm6, ymm10 vpxor ymm7, ymm7, ymm11 vmovdqa ymmword ptr [rsp+0x200], ymm8 vpsrld ymm8, ymm4, 7 vpslld ymm4, ymm4, 25 vpor ymm4, ymm4, ymm8 vpsrld ymm8, ymm5, 7 vpslld ymm5, ymm5, 25 vpor ymm5, ymm5, ymm8 vpsrld ymm8, ymm6, 7 vpslld ymm6, ymm6, 25 vpor ymm6, ymm6, ymm8 vpsrld ymm8, ymm7, 7 vpslld ymm7, ymm7, 25 vpor ymm7, ymm7, ymm8 vpaddd ymm0, ymm0, ymmword ptr [rsp+0x1A0] vpaddd ymm1, ymm1, ymmword ptr [rsp] vpaddd ymm2, ymm2, ymmword ptr [rsp+0x40] vpaddd ymm3, ymm3, ymmword ptr [rsp+0x80] vpaddd ymm0, ymm0, ymm5 vpaddd ymm1, ymm1, ymm6 vpaddd ymm2, ymm2, ymm7 vpaddd ymm3, ymm3, ymm4 vpxor ymm15, ymm15, ymm0 vpxor ymm12, ymm12, ymm1 vpxor ymm13, ymm13, ymm2 vpxor ymm14, ymm14, ymm3 vbroadcasti128 ymm8, xmmword ptr [ROT16+rip] vpshufb ymm15, ymm15, ymm8 vpshufb ymm12, ymm12, ymm8 vpshufb ymm13, ymm13, ymm8 vpshufb ymm14, ymm14, ymm8 vpaddd ymm10, ymm10, ymm15 vpaddd ymm11, ymm11, ymm12 vpaddd ymm8, ymm13, ymmword ptr [rsp+0x200] vpaddd ymm9, ymm9, ymm14 vpxor ymm5, ymm5, ymm10 vpxor ymm6, ymm6, ymm11 vpxor ymm7, ymm7, ymm8 vpxor ymm4, ymm4, ymm9 vmovdqa ymmword ptr [rsp+0x200], ymm8 vpsrld ymm8, ymm5, 12 vpslld ymm5, ymm5, 20 vpor ymm5, ymm5, ymm8 vpsrld ymm8, ymm6, 12 vpslld ymm6, ymm6, 20 vpor ymm6, ymm6, ymm8 vpsrld ymm8, ymm7, 12 vpslld ymm7, ymm7, 20 vpor ymm7, ymm7, ymm8 vpsrld ymm8, ymm4, 12 vpslld ymm4, ymm4, 20 vpor ymm4, ymm4, ymm8 vpaddd ymm0, ymm0, ymmword ptr [rsp+0x60] vpaddd ymm1, ymm1, ymmword ptr [rsp+0x140] vpaddd ymm2, ymm2, ymmword ptr [rsp+0xC0] vpaddd ymm3, ymm3, ymmword ptr [rsp+0xE0] vpaddd ymm0, ymm0, ymm5 vpaddd ymm1, ymm1, ymm6 vpaddd ymm2, ymm2, ymm7 vpaddd ymm3, ymm3, ymm4 vpxor ymm15, ymm15, ymm0 vpxor ymm12, ymm12, ymm1 vpxor ymm13, ymm13, ymm2 vpxor ymm14, ymm14, ymm3 vbroadcasti128 ymm8, xmmword ptr [ROT8+rip] vpshufb ymm15, ymm15, ymm8 vpshufb ymm12, ymm12, ymm8 vpshufb ymm13, ymm13, ymm8 vpshufb ymm14, ymm14, ymm8 vpaddd ymm10, ymm10, ymm15 vpaddd ymm11, ymm11, ymm12 vpaddd ymm8, ymm13, ymmword ptr [rsp+0x200] vpaddd ymm9, ymm9, ymm14 vpxor ymm5, ymm5, ymm10 vpxor ymm6, ymm6, ymm11 vpxor ymm7, ymm7, ymm8 vpxor ymm4, ymm4, ymm9 vmovdqa ymmword ptr [rsp+0x200], ymm8 vpsrld ymm8, ymm5, 7 vpslld ymm5, ymm5, 25 vpor ymm5, ymm5, ymm8 vpsrld ymm8, ymm6, 7 vpslld ymm6, ymm6, 25 vpor ymm6, ymm6, ymm8 vpsrld ymm8, ymm7, 7 vpslld ymm7, ymm7, 25 vpor ymm7, ymm7, ymm8 vpsrld ymm8, ymm4, 7 vpslld ymm4, ymm4, 25 vpor ymm4, ymm4, ymm8 vpaddd ymm0, ymm0, ymmword ptr [rsp+0x160] vpaddd ymm1, ymm1, ymmword ptr [rsp+0xA0] vpaddd ymm2, ymm2, ymmword ptr [rsp+0x20] vpaddd ymm3, ymm3, ymmword ptr [rsp+0x100] vpaddd ymm0, ymm0, ymm4 vpaddd ymm1, ymm1, ymm5 vpaddd ymm2, ymm2, ymm6 vpaddd ymm3, ymm3, ymm7 vpxor ymm12, ymm12, ymm0 vpxor ymm13, ymm13, ymm1 vpxor ymm14, ymm14, ymm2 vpxor ymm15, ymm15, ymm3 vbroadcasti128 ymm8, xmmword ptr [ROT16+rip] vpshufb ymm12, ymm12, ymm8 vpshufb ymm13, ymm13, ymm8 vpshufb ymm14, ymm14, ymm8 vpshufb ymm15, ymm15, ymm8 vpaddd ymm8, ymm12, ymmword ptr [rsp+0x200] vpaddd ymm9, ymm9, ymm13 vpaddd ymm10, ymm10, ymm14 vpaddd ymm11, ymm11, ymm15 vpxor ymm4, ymm4, ymm8 vpxor ymm5, ymm5, ymm9 vpxor ymm6, ymm6, ymm10 vpxor ymm7, ymm7, ymm11 vmovdqa ymmword ptr [rsp+0x200], ymm8 vpsrld ymm8, ymm4, 12 vpslld ymm4, ymm4, 20 vpor ymm4, ymm4, ymm8 vpsrld ymm8, ymm5, 12 vpslld ymm5, ymm5, 20 vpor ymm5, ymm5, ymm8 vpsrld ymm8, ymm6, 12 vpslld ymm6, ymm6, 20 vpor ymm6, ymm6, ymm8 vpsrld ymm8, ymm7, 12 vpslld ymm7, ymm7, 20 vpor ymm7, ymm7, ymm8 vpaddd ymm0, ymm0, ymmword ptr [rsp+0x1E0] vpaddd ymm1, ymm1, ymmword ptr [rsp] vpaddd ymm2, ymm2, ymmword ptr [rsp+0x120] vpaddd ymm3, ymm3, ymmword ptr [rsp+0xC0] vpaddd ymm0, ymm0, ymm4 vpaddd ymm1, ymm1, ymm5 vpaddd ymm2, ymm2, ymm6 vpaddd ymm3, ymm3, ymm7 vpxor ymm12, ymm12, ymm0 vpxor ymm13, ymm13, ymm1 vpxor ymm14, ymm14, ymm2 vpxor ymm15, ymm15, ymm3 vbroadcasti128 ymm8, xmmword ptr [ROT8+rip] vpshufb ymm12, ymm12, ymm8 vpshufb ymm13, ymm13, ymm8 vpshufb ymm14, ymm14, ymm8 vpshufb ymm15, ymm15, ymm8 vpaddd ymm8, ymm12, ymmword ptr [rsp+0x200] vpaddd ymm9, ymm9, ymm13 vpaddd ymm10, ymm10, ymm14 vpaddd ymm11, ymm11, ymm15 vpxor ymm4, ymm4, ymm8 vpxor ymm5, ymm5, ymm9 vpxor ymm6, ymm6, ymm10 vpxor ymm7, ymm7, ymm11 vmovdqa ymmword ptr [rsp+0x200], ymm8 vpsrld ymm8, ymm4, 7 vpslld ymm4, ymm4, 25 vpor ymm4, ymm4, ymm8 vpsrld ymm8, ymm5, 7 vpslld ymm5, ymm5, 25 vpor ymm5, ymm5, ymm8 vpsrld ymm8, ymm6, 7 vpslld ymm6, ymm6, 25 vpor ymm6, ymm6, ymm8 vpsrld ymm8, ymm7, 7 vpslld ymm7, ymm7, 25 vpor ymm7, ymm7, ymm8 vpaddd ymm0, ymm0, ymmword ptr [rsp+0x1C0] vpaddd ymm1, ymm1, ymmword ptr [rsp+0x40] vpaddd ymm2, ymm2, ymmword ptr [rsp+0x60] vpaddd ymm3, ymm3, ymmword ptr [rsp+0xE0] vpaddd ymm0, ymm0, ymm5 vpaddd ymm1, ymm1, ymm6 vpaddd ymm2, ymm2, ymm7 vpaddd ymm3, ymm3, ymm4 vpxor ymm15, ymm15, ymm0 vpxor ymm12, ymm12, ymm1 vpxor ymm13, ymm13, ymm2 vpxor ymm14, ymm14, ymm3 vbroadcasti128 ymm8, xmmword ptr [ROT16+rip] vpshufb ymm15, ymm15, ymm8 vpshufb ymm12, ymm12, ymm8 vpshufb ymm13, ymm13, ymm8 vpshufb ymm14, ymm14, ymm8 vpaddd ymm10, ymm10, ymm15 vpaddd ymm11, ymm11, ymm12 vpaddd ymm8, ymm13, ymmword ptr [rsp+0x200] vpaddd ymm9, ymm9, ymm14 vpxor ymm5, ymm5, ymm10 vpxor ymm6, ymm6, ymm11 vpxor ymm7, ymm7, ymm8 vpxor ymm4, ymm4, ymm9 vmovdqa ymmword ptr [rsp+0x200], ymm8 vpsrld ymm8, ymm5, 12 vpslld ymm5, ymm5, 20 vpor ymm5, ymm5, ymm8 vpsrld ymm8, ymm6, 12 vpslld ymm6, ymm6, 20 vpor ymm6, ymm6, ymm8 vpsrld ymm8, ymm7, 12 vpslld ymm7, ymm7, 20 vpor ymm7, ymm7, ymm8 vpsrld ymm8, ymm4, 12 vpslld ymm4, ymm4, 20 vpor ymm4, ymm4, ymm8 vpaddd ymm0, ymm0, ymmword ptr [rsp+0x140] vpaddd ymm1, ymm1, ymmword ptr [rsp+0x180] vpaddd ymm2, ymm2, ymmword ptr [rsp+0x80] vpaddd ymm3, ymm3, ymmword ptr [rsp+0x1A0] vpaddd ymm0, ymm0, ymm5 vpaddd ymm1, ymm1, ymm6 vpaddd ymm2, ymm2, ymm7 vpaddd ymm3, ymm3, ymm4 vpxor ymm15, ymm15, ymm0 vpxor ymm12, ymm12, ymm1 vpxor ymm13, ymm13, ymm2 vpxor ymm14, ymm14, ymm3 vbroadcasti128 ymm8, xmmword ptr [ROT8+rip] vpshufb ymm15, ymm15, ymm8 vpshufb ymm12, ymm12, ymm8 vpshufb ymm13, ymm13, ymm8 vpshufb ymm14, ymm14, ymm8 vpaddd ymm10, ymm10, ymm15 vpaddd ymm11, ymm11, ymm12 vpaddd ymm8, ymm13, ymmword ptr [rsp+0x200] vpaddd ymm9, ymm9, ymm14 vpxor ymm5, ymm5, ymm10 vpxor ymm6, ymm6, ymm11 vpxor ymm7, ymm7, ymm8 vpxor ymm4, ymm4, ymm9 vpxor ymm0, ymm0, ymm8 vpxor ymm1, ymm1, ymm9 vpxor ymm2, ymm2, ymm10 vpxor ymm3, ymm3, ymm11 vpsrld ymm8, ymm5, 7 vpslld ymm5, ymm5, 25 vpor ymm5, ymm5, ymm8 vpsrld ymm8, ymm6, 7 vpslld ymm6, ymm6, 25 vpor ymm6, ymm6, ymm8 vpsrld ymm8, ymm7, 7 vpslld ymm7, ymm7, 25 vpor ymm7, ymm7, ymm8 vpsrld ymm8, ymm4, 7 vpslld ymm4, ymm4, 25 vpor ymm4, ymm4, ymm8 vpxor ymm4, ymm4, ymm12 vpxor ymm5, ymm5, ymm13 vpxor ymm6, ymm6, ymm14 vpxor ymm7, ymm7, ymm15 movzx eax, byte ptr [rbp+0x78] jne 9b mov rbx, qword ptr [rbp+0x90] vunpcklps ymm8, ymm0, ymm1 vunpcklps ymm9, ymm2, ymm3 vunpckhps ymm10, ymm0, ymm1 vunpcklps ymm11, ymm4, ymm5 vunpcklps ymm0, ymm6, ymm7 vshufps ymm12, ymm8, ymm9, 78 vblendps ymm1, ymm8, ymm12, 0xCC vshufps ymm8, ymm11, ymm0, 78 vunpckhps ymm13, ymm2, ymm3 vblendps ymm2, ymm11, ymm8, 0xCC vblendps ymm3, ymm12, ymm9, 0xCC vperm2f128 ymm12, ymm1, ymm2, 0x20 vmovups ymmword ptr [rbx], ymm12 vunpckhps ymm14, ymm4, ymm5 vblendps ymm4, ymm8, ymm0, 0xCC vunpckhps ymm15, ymm6, ymm7 vperm2f128 ymm7, ymm3, ymm4, 0x20 vmovups ymmword ptr [rbx+0x20], ymm7 vshufps ymm5, ymm10, ymm13, 78 vblendps ymm6, ymm5, ymm13, 0xCC vshufps ymm13, ymm14, ymm15, 78 vblendps ymm10, ymm10, ymm5, 0xCC vblendps ymm14, ymm14, ymm13, 0xCC vperm2f128 ymm8, ymm10, ymm14, 0x20 vmovups ymmword ptr [rbx+0x40], ymm8 vblendps ymm15, ymm13, ymm15, 0xCC vperm2f128 ymm13, ymm6, ymm15, 0x20 vmovups ymmword ptr [rbx+0x60], ymm13 vperm2f128 ymm9, ymm1, ymm2, 0x31 vperm2f128 ymm11, ymm3, ymm4, 0x31 vmovups ymmword ptr [rbx+0x80], ymm9 vperm2f128 ymm14, ymm10, ymm14, 0x31 vperm2f128 ymm15, ymm6, ymm15, 0x31 vmovups ymmword ptr [rbx+0xA0], ymm11 vmovups ymmword ptr [rbx+0xC0], ymm14 vmovups ymmword ptr [rbx+0xE0], ymm15 vmovdqa ymm0, ymmword ptr [rsp+0x2A0] vpaddd ymm1, ymm0, ymmword ptr [rsp+0x220] vmovdqa ymmword ptr [rsp+0x220], ymm1 vpxor ymm0, ymm0, ymmword ptr [CMP_MSB_MASK+rip] vpxor ymm2, ymm1, ymmword ptr [CMP_MSB_MASK+rip] vpcmpgtd ymm2, ymm0, ymm2 vmovdqa ymm0, ymmword ptr [rsp+0x240] vpsubd ymm2, ymm0, ymm2 vmovdqa ymmword ptr [rsp+0x240], ymm2 add rdi, 64 add rbx, 256 mov qword ptr [rbp+0x90], rbx sub rsi, 8 cmp rsi, 8 jnc 2b test rsi, rsi jnz 3f 4: vzeroupper vmovdqa xmm6, xmmword ptr [rsp+0x2D0] vmovdqa xmm7, xmmword ptr [rsp+0x2E0] vmovdqa xmm8, xmmword ptr [rsp+0x2F0] vmovdqa xmm9, xmmword ptr [rsp+0x300] vmovdqa xmm10, xmmword ptr [rsp+0x310] vmovdqa xmm11, xmmword ptr [rsp+0x320] vmovdqa xmm12, xmmword ptr [rsp+0x330] vmovdqa xmm13, xmmword ptr [rsp+0x340] vmovdqa xmm14, xmmword ptr [rsp+0x350] vmovdqa xmm15, xmmword ptr [rsp+0x360] mov rsp, rbp pop rbp pop rbx pop rdi pop rsi pop r12 pop r13 pop r14 pop r15 ret .p2align 5 3: mov rbx, qword ptr [rbp+0x90] mov r15, qword ptr [rsp+0x2C0] movzx r13d, byte ptr [rbp+0x78] movzx r12d, byte ptr [rbp+0x88] test rsi, 0x4 je 3f vbroadcasti128 ymm0, xmmword ptr [rcx] vbroadcasti128 ymm1, xmmword ptr [rcx+0x10] vmovdqa ymm8, ymm0 vmovdqa ymm9, ymm1 vbroadcasti128 ymm12, xmmword ptr [rsp+0x220] vbroadcasti128 ymm13, xmmword ptr [rsp+0x240] vpunpckldq ymm14, ymm12, ymm13 vpunpckhdq ymm15, ymm12, ymm13 vpermq ymm14, ymm14, 0x50 vpermq ymm15, ymm15, 0x50 vbroadcasti128 ymm12, xmmword ptr [BLAKE3_BLOCK_LEN+rip] vpblendd ymm14, ymm14, ymm12, 0x44 vpblendd ymm15, ymm15, ymm12, 0x44 vmovdqa ymmword ptr [rsp], ymm14 vmovdqa ymmword ptr [rsp+0x20], ymm15 mov r8, qword ptr [rdi] mov r9, qword ptr [rdi+0x8] mov r10, qword ptr [rdi+0x10] mov r11, qword ptr [rdi+0x18] movzx eax, byte ptr [rbp+0x80] or eax, r13d xor edx, edx .p2align 5 2: mov r14d, eax or eax, r12d add rdx, 64 cmp rdx, r15 cmovne eax, r14d mov dword ptr [rsp+0x200], eax vmovups ymm2, ymmword ptr [r8+rdx-0x40] vinsertf128 ymm2, ymm2, xmmword ptr [r9+rdx-0x40], 0x01 vmovups ymm3, ymmword ptr [r8+rdx-0x30] vinsertf128 ymm3, ymm3, xmmword ptr [r9+rdx-0x30], 0x01 vshufps ymm4, ymm2, ymm3, 136 vshufps ymm5, ymm2, ymm3, 221 vmovups ymm2, ymmword ptr [r8+rdx-0x20] vinsertf128 ymm2, ymm2, xmmword ptr [r9+rdx-0x20], 0x01 vmovups ymm3, ymmword ptr [r8+rdx-0x10] vinsertf128 ymm3, ymm3, xmmword ptr [r9+rdx-0x10], 0x01 vshufps ymm6, ymm2, ymm3, 136 vshufps ymm7, ymm2, ymm3, 221 vpshufd ymm6, ymm6, 0x93 vpshufd ymm7, ymm7, 0x93 vmovups ymm10, ymmword ptr [r10+rdx-0x40] vinsertf128 ymm10, ymm10, xmmword ptr [r11+rdx-0x40], 0x01 vmovups ymm11, ymmword ptr [r10+rdx-0x30] vinsertf128 ymm11, ymm11, xmmword ptr [r11+rdx-0x30], 0x01 vshufps ymm12, ymm10, ymm11, 136 vshufps ymm13, ymm10, ymm11, 221 vmovups ymm10, ymmword ptr [r10+rdx-0x20] vinsertf128 ymm10, ymm10, xmmword ptr [r11+rdx-0x20], 0x01 vmovups ymm11, ymmword ptr [r10+rdx-0x10] vinsertf128 ymm11, ymm11, xmmword ptr [r11+rdx-0x10], 0x01 vshufps ymm14, ymm10, ymm11, 136 vshufps ymm15, ymm10, ymm11, 221 vpshufd ymm14, ymm14, 0x93 vpshufd ymm15, ymm15, 0x93 vpbroadcastd ymm2, dword ptr [rsp+0x200] vmovdqa ymm3, ymmword ptr [rsp] vmovdqa ymm11, ymmword ptr [rsp+0x20] vpblendd ymm3, ymm3, ymm2, 0x88 vpblendd ymm11, ymm11, ymm2, 0x88 vbroadcasti128 ymm2, xmmword ptr [BLAKE3_IV+rip] vmovdqa ymm10, ymm2 mov al, 7 9: vpaddd ymm0, ymm0, ymm4 vpaddd ymm8, ymm8, ymm12 vmovdqa ymmword ptr [rsp+0x40], ymm4 nop vmovdqa ymmword ptr [rsp+0x60], ymm12 nop vpaddd ymm0, ymm0, ymm1 vpaddd ymm8, ymm8, ymm9 vpxor ymm3, ymm3, ymm0 vpxor ymm11, ymm11, ymm8 vbroadcasti128 ymm4, xmmword ptr [ROT16+rip] vpshufb ymm3, ymm3, ymm4 vpshufb ymm11, ymm11, ymm4 vpaddd ymm2, ymm2, ymm3 vpaddd ymm10, ymm10, ymm11 vpxor ymm1, ymm1, ymm2 vpxor ymm9, ymm9, ymm10 vpsrld ymm4, ymm1, 12 vpslld ymm1, ymm1, 20 vpor ymm1, ymm1, ymm4 vpsrld ymm4, ymm9, 12 vpslld ymm9, ymm9, 20 vpor ymm9, ymm9, ymm4 vpaddd ymm0, ymm0, ymm5 vpaddd ymm8, ymm8, ymm13 vpaddd ymm0, ymm0, ymm1 vpaddd ymm8, ymm8, ymm9 vmovdqa ymmword ptr [rsp+0x80], ymm5 vmovdqa ymmword ptr [rsp+0xA0], ymm13 vpxor ymm3, ymm3, ymm0 vpxor ymm11, ymm11, ymm8 vbroadcasti128 ymm4, xmmword ptr [ROT8+rip] vpshufb ymm3, ymm3, ymm4 vpshufb ymm11, ymm11, ymm4 vpaddd ymm2, ymm2, ymm3 vpaddd ymm10, ymm10, ymm11 vpxor ymm1, ymm1, ymm2 vpxor ymm9, ymm9, ymm10 vpsrld ymm4, ymm1, 7 vpslld ymm1, ymm1, 25 vpor ymm1, ymm1, ymm4 vpsrld ymm4, ymm9, 7 vpslld ymm9, ymm9, 25 vpor ymm9, ymm9, ymm4 vpshufd ymm0, ymm0, 0x93 vpshufd ymm8, ymm8, 0x93 vpshufd ymm3, ymm3, 0x4E vpshufd ymm11, ymm11, 0x4E vpshufd ymm2, ymm2, 0x39 vpshufd ymm10, ymm10, 0x39 vpaddd ymm0, ymm0, ymm6 vpaddd ymm8, ymm8, ymm14 vpaddd ymm0, ymm0, ymm1 vpaddd ymm8, ymm8, ymm9 vpxor ymm3, ymm3, ymm0 vpxor ymm11, ymm11, ymm8 vbroadcasti128 ymm4, xmmword ptr [ROT16+rip] vpshufb ymm3, ymm3, ymm4 vpshufb ymm11, ymm11, ymm4 vpaddd ymm2, ymm2, ymm3 vpaddd ymm10, ymm10, ymm11 vpxor ymm1, ymm1, ymm2 vpxor ymm9, ymm9, ymm10 vpsrld ymm4, ymm1, 12 vpslld ymm1, ymm1, 20 vpor ymm1, ymm1, ymm4 vpsrld ymm4, ymm9, 12 vpslld ymm9, ymm9, 20 vpor ymm9, ymm9, ymm4 vpaddd ymm0, ymm0, ymm7 vpaddd ymm8, ymm8, ymm15 vpaddd ymm0, ymm0, ymm1 vpaddd ymm8, ymm8, ymm9 vpxor ymm3, ymm3, ymm0 vpxor ymm11, ymm11, ymm8 vbroadcasti128 ymm4, xmmword ptr [ROT8+rip] vpshufb ymm3, ymm3, ymm4 vpshufb ymm11, ymm11, ymm4 vpaddd ymm2, ymm2, ymm3 vpaddd ymm10, ymm10, ymm11 vpxor ymm1, ymm1, ymm2 vpxor ymm9, ymm9, ymm10 vpsrld ymm4, ymm1, 7 vpslld ymm1, ymm1, 25 vpor ymm1, ymm1, ymm4 vpsrld ymm4, ymm9, 7 vpslld ymm9, ymm9, 25 vpor ymm9, ymm9, ymm4 vpshufd ymm0, ymm0, 0x39 vpshufd ymm8, ymm8, 0x39 vpshufd ymm3, ymm3, 0x4E vpshufd ymm11, ymm11, 0x4E vpshufd ymm2, ymm2, 0x93 vpshufd ymm10, ymm10, 0x93 dec al je 9f vmovdqa ymm4, ymmword ptr [rsp+0x40] vmovdqa ymm5, ymmword ptr [rsp+0x80] vshufps ymm12, ymm4, ymm5, 214 vpshufd ymm13, ymm4, 0x0F vpshufd ymm4, ymm12, 0x39 vshufps ymm12, ymm6, ymm7, 250 vpblendd ymm13, ymm13, ymm12, 0xAA vpunpcklqdq ymm12, ymm7, ymm5 vpblendd ymm12, ymm12, ymm6, 0x88 vpshufd ymm12, ymm12, 0x78 vpunpckhdq ymm5, ymm5, ymm7 vpunpckldq ymm6, ymm6, ymm5 vpshufd ymm7, ymm6, 0x1E vmovdqa ymmword ptr [rsp+0x40], ymm13 vmovdqa ymmword ptr [rsp+0x80], ymm12 vmovdqa ymm12, ymmword ptr [rsp+0x60] vmovdqa ymm13, ymmword ptr [rsp+0xA0] vshufps ymm5, ymm12, ymm13, 214 vpshufd ymm6, ymm12, 0x0F vpshufd ymm12, ymm5, 0x39 vshufps ymm5, ymm14, ymm15, 250 vpblendd ymm6, ymm6, ymm5, 0xAA vpunpcklqdq ymm5, ymm15, ymm13 vpblendd ymm5, ymm5, ymm14, 0x88 vpshufd ymm5, ymm5, 0x78 vpunpckhdq ymm13, ymm13, ymm15 vpunpckldq ymm14, ymm14, ymm13 vpshufd ymm15, ymm14, 0x1E vmovdqa ymm13, ymm6 vmovdqa ymm14, ymm5 vmovdqa ymm5, ymmword ptr [rsp+0x40] vmovdqa ymm6, ymmword ptr [rsp+0x80] jmp 9b 9: vpxor ymm0, ymm0, ymm2 vpxor ymm1, ymm1, ymm3 vpxor ymm8, ymm8, ymm10 vpxor ymm9, ymm9, ymm11 mov eax, r13d cmp rdx, r15 jne 2b vmovdqu xmmword ptr [rbx], xmm0 vmovdqu xmmword ptr [rbx+0x10], xmm1 vextracti128 xmmword ptr [rbx+0x20], ymm0, 0x01 vextracti128 xmmword ptr [rbx+0x30], ymm1, 0x01 vmovdqu xmmword ptr [rbx+0x40], xmm8 vmovdqu xmmword ptr [rbx+0x50], xmm9 vextracti128 xmmword ptr [rbx+0x60], ymm8, 0x01 vextracti128 xmmword ptr [rbx+0x70], ymm9, 0x01 vmovaps xmm8, xmmword ptr [rsp+0x260] vmovaps xmm0, xmmword ptr [rsp+0x220] vmovaps xmm1, xmmword ptr [rsp+0x230] vmovaps xmm2, xmmword ptr [rsp+0x240] vmovaps xmm3, xmmword ptr [rsp+0x250] vblendvps xmm0, xmm0, xmm1, xmm8 vblendvps xmm2, xmm2, xmm3, xmm8 vmovaps xmmword ptr [rsp+0x220], xmm0 vmovaps xmmword ptr [rsp+0x240], xmm2 add rbx, 128 add rdi, 32 sub rsi, 4 3: test rsi, 0x2 je 3f vbroadcasti128 ymm0, xmmword ptr [rcx] vbroadcasti128 ymm1, xmmword ptr [rcx+0x10] vmovd xmm13, dword ptr [rsp+0x220] vpinsrd xmm13, xmm13, dword ptr [rsp+0x240], 1 vpinsrd xmm13, xmm13, dword ptr [BLAKE3_BLOCK_LEN+rip], 2 vmovd xmm14, dword ptr [rsp+0x224] vpinsrd xmm14, xmm14, dword ptr [rsp+0x244], 1 vpinsrd xmm14, xmm14, dword ptr [BLAKE3_BLOCK_LEN+rip], 2 vinserti128 ymm13, ymm13, xmm14, 0x01 vbroadcasti128 ymm14, xmmword ptr [ROT16+rip] vbroadcasti128 ymm15, xmmword ptr [ROT8+rip] mov r8, qword ptr [rdi] mov r9, qword ptr [rdi+0x8] movzx eax, byte ptr [rbp+0x80] or eax, r13d xor edx, edx .p2align 5 2: mov r14d, eax or eax, r12d add rdx, 64 cmp rdx, r15 cmovne eax, r14d mov dword ptr [rsp+0x200], eax vbroadcasti128 ymm2, xmmword ptr [BLAKE3_IV+rip] vpbroadcastd ymm8, dword ptr [rsp+0x200] vpblendd ymm3, ymm13, ymm8, 0x88 vmovups ymm8, ymmword ptr [r8+rdx-0x40] vinsertf128 ymm8, ymm8, xmmword ptr [r9+rdx-0x40], 0x01 vmovups ymm9, ymmword ptr [r8+rdx-0x30] vinsertf128 ymm9, ymm9, xmmword ptr [r9+rdx-0x30], 0x01 vshufps ymm4, ymm8, ymm9, 136 vshufps ymm5, ymm8, ymm9, 221 vmovups ymm8, ymmword ptr [r8+rdx-0x20] vinsertf128 ymm8, ymm8, xmmword ptr [r9+rdx-0x20], 0x01 vmovups ymm9, ymmword ptr [r8+rdx-0x10] vinsertf128 ymm9, ymm9, xmmword ptr [r9+rdx-0x10], 0x01 vshufps ymm6, ymm8, ymm9, 136 vshufps ymm7, ymm8, ymm9, 221 vpshufd ymm6, ymm6, 0x93 vpshufd ymm7, ymm7, 0x93 mov al, 7 9: vpaddd ymm0, ymm0, ymm4 vpaddd ymm0, ymm0, ymm1 vpxor ymm3, ymm3, ymm0 vpshufb ymm3, ymm3, ymm14 vpaddd ymm2, ymm2, ymm3 vpxor ymm1, ymm1, ymm2 vpsrld ymm8, ymm1, 12 vpslld ymm1, ymm1, 20 vpor ymm1, ymm1, ymm8 vpaddd ymm0, ymm0, ymm5 vpaddd ymm0, ymm0, ymm1 vpxor ymm3, ymm3, ymm0 vpshufb ymm3, ymm3, ymm15 vpaddd ymm2, ymm2, ymm3 vpxor ymm1, ymm1, ymm2 vpsrld ymm8, ymm1, 7 vpslld ymm1, ymm1, 25 vpor ymm1, ymm1, ymm8 vpshufd ymm0, ymm0, 0x93 vpshufd ymm3, ymm3, 0x4E vpshufd ymm2, ymm2, 0x39 vpaddd ymm0, ymm0, ymm6 vpaddd ymm0, ymm0, ymm1 vpxor ymm3, ymm3, ymm0 vpshufb ymm3, ymm3, ymm14 vpaddd ymm2, ymm2, ymm3 vpxor ymm1, ymm1, ymm2 vpsrld ymm8, ymm1, 12 vpslld ymm1, ymm1, 20 vpor ymm1, ymm1, ymm8 vpaddd ymm0, ymm0, ymm7 vpaddd ymm0, ymm0, ymm1 vpxor ymm3, ymm3, ymm0 vpshufb ymm3, ymm3, ymm15 vpaddd ymm2, ymm2, ymm3 vpxor ymm1, ymm1, ymm2 vpsrld ymm8, ymm1, 7 vpslld ymm1, ymm1, 25 vpor ymm1, ymm1, ymm8 vpshufd ymm0, ymm0, 0x39 vpshufd ymm3, ymm3, 0x4E vpshufd ymm2, ymm2, 0x93 dec al jz 9f vshufps ymm8, ymm4, ymm5, 214 vpshufd ymm9, ymm4, 0x0F vpshufd ymm4, ymm8, 0x39 vshufps ymm8, ymm6, ymm7, 250 vpblendd ymm9, ymm9, ymm8, 0xAA vpunpcklqdq ymm8, ymm7, ymm5 vpblendd ymm8, ymm8, ymm6, 0x88 vpshufd ymm8, ymm8, 0x78 vpunpckhdq ymm5, ymm5, ymm7 vpunpckldq ymm6, ymm6, ymm5 vpshufd ymm7, ymm6, 0x1E vmovdqa ymm5, ymm9 vmovdqa ymm6, ymm8 jmp 9b 9: vpxor ymm0, ymm0, ymm2 vpxor ymm1, ymm1, ymm3 mov eax, r13d cmp rdx, r15 jne 2b vmovdqu xmmword ptr [rbx], xmm0 vmovdqu xmmword ptr [rbx+0x10], xmm1 vextracti128 xmmword ptr [rbx+0x20], ymm0, 0x01 vextracti128 xmmword ptr [rbx+0x30], ymm1, 0x01 vmovaps ymm8, ymmword ptr [rsp+0x260] vmovaps ymm0, ymmword ptr [rsp+0x220] vmovups ymm1, ymmword ptr [rsp+0x228] vmovaps ymm2, ymmword ptr [rsp+0x240] vmovups ymm3, ymmword ptr [rsp+0x248] vblendvps ymm0, ymm0, ymm1, ymm8 vblendvps ymm2, ymm2, ymm3, ymm8 vmovaps ymmword ptr [rsp+0x220], ymm0 vmovaps ymmword ptr [rsp+0x240], ymm2 add rbx, 64 add rdi, 16 sub rsi, 2 3: test rsi, 0x1 je 4b vmovdqu xmm0, xmmword ptr [rcx] vmovdqu xmm1, xmmword ptr [rcx+0x10] vmovd xmm3, dword ptr [rsp+0x220] vpinsrd xmm3, xmm3, dword ptr [rsp+0x240], 1 vpinsrd xmm13, xmm3, dword ptr [BLAKE3_BLOCK_LEN+rip], 2 vmovdqa xmm14, xmmword ptr [ROT16+rip] vmovdqa xmm15, xmmword ptr [ROT8+rip] mov r8, qword ptr [rdi] movzx eax, byte ptr [rbp+0x80] or eax, r13d xor edx, edx .p2align 5 2: mov r14d, eax or eax, r12d add rdx, 64 cmp rdx, r15 cmovne eax, r14d vmovdqa xmm2, xmmword ptr [BLAKE3_IV+rip] vmovdqa xmm3, xmm13 vpinsrd xmm3, xmm3, eax, 3 vmovups xmm8, xmmword ptr [r8+rdx-0x40] vmovups xmm9, xmmword ptr [r8+rdx-0x30] vshufps xmm4, xmm8, xmm9, 136 vshufps xmm5, xmm8, xmm9, 221 vmovups xmm8, xmmword ptr [r8+rdx-0x20] vmovups xmm9, xmmword ptr [r8+rdx-0x10] vshufps xmm6, xmm8, xmm9, 136 vshufps xmm7, xmm8, xmm9, 221 vpshufd xmm6, xmm6, 0x93 vpshufd xmm7, xmm7, 0x93 mov al, 7 9: vpaddd xmm0, xmm0, xmm4 vpaddd xmm0, xmm0, xmm1 vpxor xmm3, xmm3, xmm0 vpshufb xmm3, xmm3, xmm14 vpaddd xmm2, xmm2, xmm3 vpxor xmm1, xmm1, xmm2 vpsrld xmm8, xmm1, 12 vpslld xmm1, xmm1, 20 vpor xmm1, xmm1, xmm8 vpaddd xmm0, xmm0, xmm5 vpaddd xmm0, xmm0, xmm1 vpxor xmm3, xmm3, xmm0 vpshufb xmm3, xmm3, xmm15 vpaddd xmm2, xmm2, xmm3 vpxor xmm1, xmm1, xmm2 vpsrld xmm8, xmm1, 7 vpslld xmm1, xmm1, 25 vpor xmm1, xmm1, xmm8 vpshufd xmm0, xmm0, 0x93 vpshufd xmm3, xmm3, 0x4E vpshufd xmm2, xmm2, 0x39 vpaddd xmm0, xmm0, xmm6 vpaddd xmm0, xmm0, xmm1 vpxor xmm3, xmm3, xmm0 vpshufb xmm3, xmm3, xmm14 vpaddd xmm2, xmm2, xmm3 vpxor xmm1, xmm1, xmm2 vpsrld xmm8, xmm1, 12 vpslld xmm1, xmm1, 20 vpor xmm1, xmm1, xmm8 vpaddd xmm0, xmm0, xmm7 vpaddd xmm0, xmm0, xmm1 vpxor xmm3, xmm3, xmm0 vpshufb xmm3, xmm3, xmm15 vpaddd xmm2, xmm2, xmm3 vpxor xmm1, xmm1, xmm2 vpsrld xmm8, xmm1, 7 vpslld xmm1, xmm1, 25 vpor xmm1, xmm1, xmm8 vpshufd xmm0, xmm0, 0x39 vpshufd xmm3, xmm3, 0x4E vpshufd xmm2, xmm2, 0x93 dec al jz 9f vshufps xmm8, xmm4, xmm5, 214 vpshufd xmm9, xmm4, 0x0F vpshufd xmm4, xmm8, 0x39 vshufps xmm8, xmm6, xmm7, 250 vpblendd xmm9, xmm9, xmm8, 0xAA vpunpcklqdq xmm8, xmm7, xmm5 vpblendd xmm8, xmm8, xmm6, 0x88 vpshufd xmm8, xmm8, 0x78 vpunpckhdq xmm5, xmm5, xmm7 vpunpckldq xmm6, xmm6, xmm5 vpshufd xmm7, xmm6, 0x1E vmovdqa xmm5, xmm9 vmovdqa xmm6, xmm8 jmp 9b 9: vpxor xmm0, xmm0, xmm2 vpxor xmm1, xmm1, xmm3 mov eax, r13d cmp rdx, r15 jne 2b vmovdqu xmmword ptr [rbx], xmm0 vmovdqu xmmword ptr [rbx+0x10], xmm1 jmp 4b .section .rdata .p2align 6 ADD0: .long 0, 1, 2, 3, 4, 5, 6, 7 ADD1: .long 8, 8, 8, 8, 8, 8, 8, 8 BLAKE3_IV_0: .long 0x6A09E667, 0x6A09E667, 0x6A09E667, 0x6A09E667 .long 0x6A09E667, 0x6A09E667, 0x6A09E667, 0x6A09E667 BLAKE3_IV_1: .long 0xBB67AE85, 0xBB67AE85, 0xBB67AE85, 0xBB67AE85 .long 0xBB67AE85, 0xBB67AE85, 0xBB67AE85, 0xBB67AE85 BLAKE3_IV_2: .long 0x3C6EF372, 0x3C6EF372, 0x3C6EF372, 0x3C6EF372 .long 0x3C6EF372, 0x3C6EF372, 0x3C6EF372, 0x3C6EF372 BLAKE3_IV_3: .long 0xA54FF53A, 0xA54FF53A, 0xA54FF53A, 0xA54FF53A .long 0xA54FF53A, 0xA54FF53A, 0xA54FF53A, 0xA54FF53A BLAKE3_BLOCK_LEN: .long 0x00000040, 0x00000040, 0x00000040, 0x00000040 .long 0x00000040, 0x00000040, 0x00000040, 0x00000040 ROT16: .byte 2, 3, 0, 1, 6, 7, 4, 5, 10, 11, 8, 9, 14, 15, 12, 13 ROT8: .byte 1, 2, 3, 0, 5, 6, 7, 4, 9, 10, 11, 8, 13, 14, 15, 12 CMP_MSB_MASK: .long 0x80000000, 0x80000000, 0x80000000, 0x80000000 .long 0x80000000, 0x80000000, 0x80000000, 0x80000000 BLAKE3_IV: .long 0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A librecast/libs/blake3/c/blake3_avx2_x86-64_windows_msvc.asm000066400000000000000000002006341502456746400237250ustar00rootroot00000000000000public _blake3_hash_many_avx2 public blake3_hash_many_avx2 _TEXT SEGMENT ALIGN(16) 'CODE' ALIGN 16 blake3_hash_many_avx2 PROC _blake3_hash_many_avx2 PROC push r15 push r14 push r13 push r12 push rsi push rdi push rbx push rbp mov rbp, rsp sub rsp, 880 and rsp, 0FFFFFFFFFFFFFFC0H vmovdqa xmmword ptr [rsp+2D0H], xmm6 vmovdqa xmmword ptr [rsp+2E0H], xmm7 vmovdqa xmmword ptr [rsp+2F0H], xmm8 vmovdqa xmmword ptr [rsp+300H], xmm9 vmovdqa xmmword ptr [rsp+310H], xmm10 vmovdqa xmmword ptr [rsp+320H], xmm11 vmovdqa xmmword ptr [rsp+330H], xmm12 vmovdqa xmmword ptr [rsp+340H], xmm13 vmovdqa xmmword ptr [rsp+350H], xmm14 vmovdqa xmmword ptr [rsp+360H], xmm15 mov rdi, rcx mov rsi, rdx mov rdx, r8 mov rcx, r9 mov r8, qword ptr [rbp+68H] movzx r9, byte ptr [rbp+70H] neg r9d vmovd xmm0, r9d vpbroadcastd ymm0, xmm0 vmovdqa ymmword ptr [rsp+260H], ymm0 vpand ymm1, ymm0, ymmword ptr [ADD0] vpand ymm2, ymm0, ymmword ptr [ADD1] vmovdqa ymmword ptr [rsp+2A0H], ymm2 vmovd xmm2, r8d vpbroadcastd ymm2, xmm2 vpaddd ymm2, ymm2, ymm1 vmovdqa ymmword ptr [rsp+220H], ymm2 vpxor ymm1, ymm1, ymmword ptr [CMP_MSB_MASK] vpxor ymm2, ymm2, ymmword ptr [CMP_MSB_MASK] vpcmpgtd ymm2, ymm1, ymm2 shr r8, 32 vmovd xmm3, r8d vpbroadcastd ymm3, xmm3 vpsubd ymm3, ymm3, ymm2 vmovdqa ymmword ptr [rsp+240H], ymm3 shl rdx, 6 mov qword ptr [rsp+2C0H], rdx cmp rsi, 8 jc final7blocks outerloop8: vpbroadcastd ymm0, dword ptr [rcx] vpbroadcastd ymm1, dword ptr [rcx+4H] vpbroadcastd ymm2, dword ptr [rcx+8H] vpbroadcastd ymm3, dword ptr [rcx+0CH] vpbroadcastd ymm4, dword ptr [rcx+10H] vpbroadcastd ymm5, dword ptr [rcx+14H] vpbroadcastd ymm6, dword ptr [rcx+18H] vpbroadcastd ymm7, dword ptr [rcx+1CH] mov r8, qword ptr [rdi] mov r9, qword ptr [rdi+8H] mov r10, qword ptr [rdi+10H] mov r11, qword ptr [rdi+18H] mov r12, qword ptr [rdi+20H] mov r13, qword ptr [rdi+28H] mov r14, qword ptr [rdi+30H] mov r15, qword ptr [rdi+38H] movzx eax, byte ptr [rbp+78H] movzx ebx, byte ptr [rbp+80H] or eax, ebx xor edx, edx ALIGN 16 innerloop8: movzx ebx, byte ptr [rbp+88H] or ebx, eax add rdx, 64 cmp rdx, qword ptr [rsp+2C0H] cmove eax, ebx mov dword ptr [rsp+200H], eax vmovups xmm8, xmmword ptr [r8+rdx-40H] vinsertf128 ymm8, ymm8, xmmword ptr [r12+rdx-40H], 01H vmovups xmm9, xmmword ptr [r9+rdx-40H] vinsertf128 ymm9, ymm9, xmmword ptr [r13+rdx-40H], 01H vunpcklpd ymm12, ymm8, ymm9 vunpckhpd ymm13, ymm8, ymm9 vmovups xmm10, xmmword ptr [r10+rdx-40H] vinsertf128 ymm10, ymm10, xmmword ptr [r14+rdx-40H], 01H vmovups xmm11, xmmword ptr [r11+rdx-40H] vinsertf128 ymm11, ymm11, xmmword ptr [r15+rdx-40H], 01H vunpcklpd ymm14, ymm10, ymm11 vunpckhpd ymm15, ymm10, ymm11 vshufps ymm8, ymm12, ymm14, 136 vmovaps ymmword ptr [rsp], ymm8 vshufps ymm9, ymm12, ymm14, 221 vmovaps ymmword ptr [rsp+20H], ymm9 vshufps ymm10, ymm13, ymm15, 136 vmovaps ymmword ptr [rsp+40H], ymm10 vshufps ymm11, ymm13, ymm15, 221 vmovaps ymmword ptr [rsp+60H], ymm11 vmovups xmm8, xmmword ptr [r8+rdx-30H] vinsertf128 ymm8, ymm8, xmmword ptr [r12+rdx-30H], 01H vmovups xmm9, xmmword ptr [r9+rdx-30H] vinsertf128 ymm9, ymm9, xmmword ptr [r13+rdx-30H], 01H vunpcklpd ymm12, ymm8, ymm9 vunpckhpd ymm13, ymm8, ymm9 vmovups xmm10, xmmword ptr [r10+rdx-30H] vinsertf128 ymm10, ymm10, xmmword ptr [r14+rdx-30H], 01H vmovups xmm11, xmmword ptr [r11+rdx-30H] vinsertf128 ymm11, ymm11, xmmword ptr [r15+rdx-30H], 01H vunpcklpd ymm14, ymm10, ymm11 vunpckhpd ymm15, ymm10, ymm11 vshufps ymm8, ymm12, ymm14, 136 vmovaps ymmword ptr [rsp+80H], ymm8 vshufps ymm9, ymm12, ymm14, 221 vmovaps ymmword ptr [rsp+0A0H], ymm9 vshufps ymm10, ymm13, ymm15, 136 vmovaps ymmword ptr [rsp+0C0H], ymm10 vshufps ymm11, ymm13, ymm15, 221 vmovaps ymmword ptr [rsp+0E0H], ymm11 vmovups xmm8, xmmword ptr [r8+rdx-20H] vinsertf128 ymm8, ymm8, xmmword ptr [r12+rdx-20H], 01H vmovups xmm9, xmmword ptr [r9+rdx-20H] vinsertf128 ymm9, ymm9, xmmword ptr [r13+rdx-20H], 01H vunpcklpd ymm12, ymm8, ymm9 vunpckhpd ymm13, ymm8, ymm9 vmovups xmm10, xmmword ptr [r10+rdx-20H] vinsertf128 ymm10, ymm10, xmmword ptr [r14+rdx-20H], 01H vmovups xmm11, xmmword ptr [r11+rdx-20H] vinsertf128 ymm11, ymm11, xmmword ptr [r15+rdx-20H], 01H vunpcklpd ymm14, ymm10, ymm11 vunpckhpd ymm15, ymm10, ymm11 vshufps ymm8, ymm12, ymm14, 136 vmovaps ymmword ptr [rsp+100H], ymm8 vshufps ymm9, ymm12, ymm14, 221 vmovaps ymmword ptr [rsp+120H], ymm9 vshufps ymm10, ymm13, ymm15, 136 vmovaps ymmword ptr [rsp+140H], ymm10 vshufps ymm11, ymm13, ymm15, 221 vmovaps ymmword ptr [rsp+160H], ymm11 vmovups xmm8, xmmword ptr [r8+rdx-10H] vinsertf128 ymm8, ymm8, xmmword ptr [r12+rdx-10H], 01H vmovups xmm9, xmmword ptr [r9+rdx-10H] vinsertf128 ymm9, ymm9, xmmword ptr [r13+rdx-10H], 01H vunpcklpd ymm12, ymm8, ymm9 vunpckhpd ymm13, ymm8, ymm9 vmovups xmm10, xmmword ptr [r10+rdx-10H] vinsertf128 ymm10, ymm10, xmmword ptr [r14+rdx-10H], 01H vmovups xmm11, xmmword ptr [r11+rdx-10H] vinsertf128 ymm11, ymm11, xmmword ptr [r15+rdx-10H], 01H vunpcklpd ymm14, ymm10, ymm11 vunpckhpd ymm15, ymm10, ymm11 vshufps ymm8, ymm12, ymm14, 136 vmovaps ymmword ptr [rsp+180H], ymm8 vshufps ymm9, ymm12, ymm14, 221 vmovaps ymmword ptr [rsp+1A0H], ymm9 vshufps ymm10, ymm13, ymm15, 136 vmovaps ymmword ptr [rsp+1C0H], ymm10 vshufps ymm11, ymm13, ymm15, 221 vmovaps ymmword ptr [rsp+1E0H], ymm11 vpbroadcastd ymm15, dword ptr [rsp+200H] prefetcht0 byte ptr [r8+rdx+80H] prefetcht0 byte ptr [r12+rdx+80H] prefetcht0 byte ptr [r9+rdx+80H] prefetcht0 byte ptr [r13+rdx+80H] prefetcht0 byte ptr [r10+rdx+80H] prefetcht0 byte ptr [r14+rdx+80H] prefetcht0 byte ptr [r11+rdx+80H] prefetcht0 byte ptr [r15+rdx+80H] vpaddd ymm0, ymm0, ymmword ptr [rsp] vpaddd ymm1, ymm1, ymmword ptr [rsp+40H] vpaddd ymm2, ymm2, ymmword ptr [rsp+80H] vpaddd ymm3, ymm3, ymmword ptr [rsp+0C0H] vpaddd ymm0, ymm0, ymm4 vpaddd ymm1, ymm1, ymm5 vpaddd ymm2, ymm2, ymm6 vpaddd ymm3, ymm3, ymm7 vpxor ymm12, ymm0, ymmword ptr [rsp+220H] vpxor ymm13, ymm1, ymmword ptr [rsp+240H] vpxor ymm14, ymm2, ymmword ptr [BLAKE3_BLOCK_LEN] vpxor ymm15, ymm3, ymm15 vbroadcasti128 ymm8, xmmword ptr [ROT16] vpshufb ymm12, ymm12, ymm8 vpshufb ymm13, ymm13, ymm8 vpshufb ymm14, ymm14, ymm8 vpshufb ymm15, ymm15, ymm8 vpaddd ymm8, ymm12, ymmword ptr [BLAKE3_IV_0] vpaddd ymm9, ymm13, ymmword ptr [BLAKE3_IV_1] vpaddd ymm10, ymm14, ymmword ptr [BLAKE3_IV_2] vpaddd ymm11, ymm15, ymmword ptr [BLAKE3_IV_3] vpxor ymm4, ymm4, ymm8 vpxor ymm5, ymm5, ymm9 vpxor ymm6, ymm6, ymm10 vpxor ymm7, ymm7, ymm11 vmovdqa ymmword ptr [rsp+200H], ymm8 vpsrld ymm8, ymm4, 12 vpslld ymm4, ymm4, 20 vpor ymm4, ymm4, ymm8 vpsrld ymm8, ymm5, 12 vpslld ymm5, ymm5, 20 vpor ymm5, ymm5, ymm8 vpsrld ymm8, ymm6, 12 vpslld ymm6, ymm6, 20 vpor ymm6, ymm6, ymm8 vpsrld ymm8, ymm7, 12 vpslld ymm7, ymm7, 20 vpor ymm7, ymm7, ymm8 vpaddd ymm0, ymm0, ymmword ptr [rsp+20H] vpaddd ymm1, ymm1, ymmword ptr [rsp+60H] vpaddd ymm2, ymm2, ymmword ptr [rsp+0A0H] vpaddd ymm3, ymm3, ymmword ptr [rsp+0E0H] vpaddd ymm0, ymm0, ymm4 vpaddd ymm1, ymm1, ymm5 vpaddd ymm2, ymm2, ymm6 vpaddd ymm3, ymm3, ymm7 vpxor ymm12, ymm12, ymm0 vpxor ymm13, ymm13, ymm1 vpxor ymm14, ymm14, ymm2 vpxor ymm15, ymm15, ymm3 vbroadcasti128 ymm8, xmmword ptr [ROT8] vpshufb ymm12, ymm12, ymm8 vpshufb ymm13, ymm13, ymm8 vpshufb ymm14, ymm14, ymm8 vpshufb ymm15, ymm15, ymm8 vpaddd ymm8, ymm12, ymmword ptr [rsp+200H] vpaddd ymm9, ymm9, ymm13 vpaddd ymm10, ymm10, ymm14 vpaddd ymm11, ymm11, ymm15 vpxor ymm4, ymm4, ymm8 vpxor ymm5, ymm5, ymm9 vpxor ymm6, ymm6, ymm10 vpxor ymm7, ymm7, ymm11 vmovdqa ymmword ptr [rsp+200H], ymm8 vpsrld ymm8, ymm4, 7 vpslld ymm4, ymm4, 25 vpor ymm4, ymm4, ymm8 vpsrld ymm8, ymm5, 7 vpslld ymm5, ymm5, 25 vpor ymm5, ymm5, ymm8 vpsrld ymm8, ymm6, 7 vpslld ymm6, ymm6, 25 vpor ymm6, ymm6, ymm8 vpsrld ymm8, ymm7, 7 vpslld ymm7, ymm7, 25 vpor ymm7, ymm7, ymm8 vpaddd ymm0, ymm0, ymmword ptr [rsp+100H] vpaddd ymm1, ymm1, ymmword ptr [rsp+140H] vpaddd ymm2, ymm2, ymmword ptr [rsp+180H] vpaddd ymm3, ymm3, ymmword ptr [rsp+1C0H] vpaddd ymm0, ymm0, ymm5 vpaddd ymm1, ymm1, ymm6 vpaddd ymm2, ymm2, ymm7 vpaddd ymm3, ymm3, ymm4 vpxor ymm15, ymm15, ymm0 vpxor ymm12, ymm12, ymm1 vpxor ymm13, ymm13, ymm2 vpxor ymm14, ymm14, ymm3 vbroadcasti128 ymm8, xmmword ptr [ROT16] vpshufb ymm15, ymm15, ymm8 vpshufb ymm12, ymm12, ymm8 vpshufb ymm13, ymm13, ymm8 vpshufb ymm14, ymm14, ymm8 vpaddd ymm10, ymm10, ymm15 vpaddd ymm11, ymm11, ymm12 vpaddd ymm8, ymm13, ymmword ptr [rsp+200H] vpaddd ymm9, ymm9, ymm14 vpxor ymm5, ymm5, ymm10 vpxor ymm6, ymm6, ymm11 vpxor ymm7, ymm7, ymm8 vpxor ymm4, ymm4, ymm9 vmovdqa ymmword ptr [rsp+200H], ymm8 vpsrld ymm8, ymm5, 12 vpslld ymm5, ymm5, 20 vpor ymm5, ymm5, ymm8 vpsrld ymm8, ymm6, 12 vpslld ymm6, ymm6, 20 vpor ymm6, ymm6, ymm8 vpsrld ymm8, ymm7, 12 vpslld ymm7, ymm7, 20 vpor ymm7, ymm7, ymm8 vpsrld ymm8, ymm4, 12 vpslld ymm4, ymm4, 20 vpor ymm4, ymm4, ymm8 vpaddd ymm0, ymm0, ymmword ptr [rsp+120H] vpaddd ymm1, ymm1, ymmword ptr [rsp+160H] vpaddd ymm2, ymm2, ymmword ptr [rsp+1A0H] vpaddd ymm3, ymm3, ymmword ptr [rsp+1E0H] vpaddd ymm0, ymm0, ymm5 vpaddd ymm1, ymm1, ymm6 vpaddd ymm2, ymm2, ymm7 vpaddd ymm3, ymm3, ymm4 vpxor ymm15, ymm15, ymm0 vpxor ymm12, ymm12, ymm1 vpxor ymm13, ymm13, ymm2 vpxor ymm14, ymm14, ymm3 vbroadcasti128 ymm8, xmmword ptr [ROT8] vpshufb ymm15, ymm15, ymm8 vpshufb ymm12, ymm12, ymm8 vpshufb ymm13, ymm13, ymm8 vpshufb ymm14, ymm14, ymm8 vpaddd ymm10, ymm10, ymm15 vpaddd ymm11, ymm11, ymm12 vpaddd ymm8, ymm13, ymmword ptr [rsp+200H] vpaddd ymm9, ymm9, ymm14 vpxor ymm5, ymm5, ymm10 vpxor ymm6, ymm6, ymm11 vpxor ymm7, ymm7, ymm8 vpxor ymm4, ymm4, ymm9 vmovdqa ymmword ptr [rsp+200H], ymm8 vpsrld ymm8, ymm5, 7 vpslld ymm5, ymm5, 25 vpor ymm5, ymm5, ymm8 vpsrld ymm8, ymm6, 7 vpslld ymm6, ymm6, 25 vpor ymm6, ymm6, ymm8 vpsrld ymm8, ymm7, 7 vpslld ymm7, ymm7, 25 vpor ymm7, ymm7, ymm8 vpsrld ymm8, ymm4, 7 vpslld ymm4, ymm4, 25 vpor ymm4, ymm4, ymm8 vpaddd ymm0, ymm0, ymmword ptr [rsp+40H] vpaddd ymm1, ymm1, ymmword ptr [rsp+60H] vpaddd ymm2, ymm2, ymmword ptr [rsp+0E0H] vpaddd ymm3, ymm3, ymmword ptr [rsp+80H] vpaddd ymm0, ymm0, ymm4 vpaddd ymm1, ymm1, ymm5 vpaddd ymm2, ymm2, ymm6 vpaddd ymm3, ymm3, ymm7 vpxor ymm12, ymm12, ymm0 vpxor ymm13, ymm13, ymm1 vpxor ymm14, ymm14, ymm2 vpxor ymm15, ymm15, ymm3 vbroadcasti128 ymm8, xmmword ptr [ROT16] vpshufb ymm12, ymm12, ymm8 vpshufb ymm13, ymm13, ymm8 vpshufb ymm14, ymm14, ymm8 vpshufb ymm15, ymm15, ymm8 vpaddd ymm8, ymm12, ymmword ptr [rsp+200H] vpaddd ymm9, ymm9, ymm13 vpaddd ymm10, ymm10, ymm14 vpaddd ymm11, ymm11, ymm15 vpxor ymm4, ymm4, ymm8 vpxor ymm5, ymm5, ymm9 vpxor ymm6, ymm6, ymm10 vpxor ymm7, ymm7, ymm11 vmovdqa ymmword ptr [rsp+200H], ymm8 vpsrld ymm8, ymm4, 12 vpslld ymm4, ymm4, 20 vpor ymm4, ymm4, ymm8 vpsrld ymm8, ymm5, 12 vpslld ymm5, ymm5, 20 vpor ymm5, ymm5, ymm8 vpsrld ymm8, ymm6, 12 vpslld ymm6, ymm6, 20 vpor ymm6, ymm6, ymm8 vpsrld ymm8, ymm7, 12 vpslld ymm7, ymm7, 20 vpor ymm7, ymm7, ymm8 vpaddd ymm0, ymm0, ymmword ptr [rsp+0C0H] vpaddd ymm1, ymm1, ymmword ptr [rsp+140H] vpaddd ymm2, ymm2, ymmword ptr [rsp] vpaddd ymm3, ymm3, ymmword ptr [rsp+1A0H] vpaddd ymm0, ymm0, ymm4 vpaddd ymm1, ymm1, ymm5 vpaddd ymm2, ymm2, ymm6 vpaddd ymm3, ymm3, ymm7 vpxor ymm12, ymm12, ymm0 vpxor ymm13, ymm13, ymm1 vpxor ymm14, ymm14, ymm2 vpxor ymm15, ymm15, ymm3 vbroadcasti128 ymm8, xmmword ptr [ROT8] vpshufb ymm12, ymm12, ymm8 vpshufb ymm13, ymm13, ymm8 vpshufb ymm14, ymm14, ymm8 vpshufb ymm15, ymm15, ymm8 vpaddd ymm8, ymm12, ymmword ptr [rsp+200H] vpaddd ymm9, ymm9, ymm13 vpaddd ymm10, ymm10, ymm14 vpaddd ymm11, ymm11, ymm15 vpxor ymm4, ymm4, ymm8 vpxor ymm5, ymm5, ymm9 vpxor ymm6, ymm6, ymm10 vpxor ymm7, ymm7, ymm11 vmovdqa ymmword ptr [rsp+200H], ymm8 vpsrld ymm8, ymm4, 7 vpslld ymm4, ymm4, 25 vpor ymm4, ymm4, ymm8 vpsrld ymm8, ymm5, 7 vpslld ymm5, ymm5, 25 vpor ymm5, ymm5, ymm8 vpsrld ymm8, ymm6, 7 vpslld ymm6, ymm6, 25 vpor ymm6, ymm6, ymm8 vpsrld ymm8, ymm7, 7 vpslld ymm7, ymm7, 25 vpor ymm7, ymm7, ymm8 vpaddd ymm0, ymm0, ymmword ptr [rsp+20H] vpaddd ymm1, ymm1, ymmword ptr [rsp+180H] vpaddd ymm2, ymm2, ymmword ptr [rsp+120H] vpaddd ymm3, ymm3, ymmword ptr [rsp+1E0H] vpaddd ymm0, ymm0, ymm5 vpaddd ymm1, ymm1, ymm6 vpaddd ymm2, ymm2, ymm7 vpaddd ymm3, ymm3, ymm4 vpxor ymm15, ymm15, ymm0 vpxor ymm12, ymm12, ymm1 vpxor ymm13, ymm13, ymm2 vpxor ymm14, ymm14, ymm3 vbroadcasti128 ymm8, xmmword ptr [ROT16] vpshufb ymm15, ymm15, ymm8 vpshufb ymm12, ymm12, ymm8 vpshufb ymm13, ymm13, ymm8 vpshufb ymm14, ymm14, ymm8 vpaddd ymm10, ymm10, ymm15 vpaddd ymm11, ymm11, ymm12 vpaddd ymm8, ymm13, ymmword ptr [rsp+200H] vpaddd ymm9, ymm9, ymm14 vpxor ymm5, ymm5, ymm10 vpxor ymm6, ymm6, ymm11 vpxor ymm7, ymm7, ymm8 vpxor ymm4, ymm4, ymm9 vmovdqa ymmword ptr [rsp+200H], ymm8 vpsrld ymm8, ymm5, 12 vpslld ymm5, ymm5, 20 vpor ymm5, ymm5, ymm8 vpsrld ymm8, ymm6, 12 vpslld ymm6, ymm6, 20 vpor ymm6, ymm6, ymm8 vpsrld ymm8, ymm7, 12 vpslld ymm7, ymm7, 20 vpor ymm7, ymm7, ymm8 vpsrld ymm8, ymm4, 12 vpslld ymm4, ymm4, 20 vpor ymm4, ymm4, ymm8 vpaddd ymm0, ymm0, ymmword ptr [rsp+160H] vpaddd ymm1, ymm1, ymmword ptr [rsp+0A0H] vpaddd ymm2, ymm2, ymmword ptr [rsp+1C0H] vpaddd ymm3, ymm3, ymmword ptr [rsp+100H] vpaddd ymm0, ymm0, ymm5 vpaddd ymm1, ymm1, ymm6 vpaddd ymm2, ymm2, ymm7 vpaddd ymm3, ymm3, ymm4 vpxor ymm15, ymm15, ymm0 vpxor ymm12, ymm12, ymm1 vpxor ymm13, ymm13, ymm2 vpxor ymm14, ymm14, ymm3 vbroadcasti128 ymm8, xmmword ptr [ROT8] vpshufb ymm15, ymm15, ymm8 vpshufb ymm12, ymm12, ymm8 vpshufb ymm13, ymm13, ymm8 vpshufb ymm14, ymm14, ymm8 vpaddd ymm10, ymm10, ymm15 vpaddd ymm11, ymm11, ymm12 vpaddd ymm8, ymm13, ymmword ptr [rsp+200H] vpaddd ymm9, ymm9, ymm14 vpxor ymm5, ymm5, ymm10 vpxor ymm6, ymm6, ymm11 vpxor ymm7, ymm7, ymm8 vpxor ymm4, ymm4, ymm9 vmovdqa ymmword ptr [rsp+200H], ymm8 vpsrld ymm8, ymm5, 7 vpslld ymm5, ymm5, 25 vpor ymm5, ymm5, ymm8 vpsrld ymm8, ymm6, 7 vpslld ymm6, ymm6, 25 vpor ymm6, ymm6, ymm8 vpsrld ymm8, ymm7, 7 vpslld ymm7, ymm7, 25 vpor ymm7, ymm7, ymm8 vpsrld ymm8, ymm4, 7 vpslld ymm4, ymm4, 25 vpor ymm4, ymm4, ymm8 vpaddd ymm0, ymm0, ymmword ptr [rsp+60H] vpaddd ymm1, ymm1, ymmword ptr [rsp+140H] vpaddd ymm2, ymm2, ymmword ptr [rsp+1A0H] vpaddd ymm3, ymm3, ymmword ptr [rsp+0E0H] vpaddd ymm0, ymm0, ymm4 vpaddd ymm1, ymm1, ymm5 vpaddd ymm2, ymm2, ymm6 vpaddd ymm3, ymm3, ymm7 vpxor ymm12, ymm12, ymm0 vpxor ymm13, ymm13, ymm1 vpxor ymm14, ymm14, ymm2 vpxor ymm15, ymm15, ymm3 vbroadcasti128 ymm8, xmmword ptr [ROT16] vpshufb ymm12, ymm12, ymm8 vpshufb ymm13, ymm13, ymm8 vpshufb ymm14, ymm14, ymm8 vpshufb ymm15, ymm15, ymm8 vpaddd ymm8, ymm12, ymmword ptr [rsp+200H] vpaddd ymm9, ymm9, ymm13 vpaddd ymm10, ymm10, ymm14 vpaddd ymm11, ymm11, ymm15 vpxor ymm4, ymm4, ymm8 vpxor ymm5, ymm5, ymm9 vpxor ymm6, ymm6, ymm10 vpxor ymm7, ymm7, ymm11 vmovdqa ymmword ptr [rsp+200H], ymm8 vpsrld ymm8, ymm4, 12 vpslld ymm4, ymm4, 20 vpor ymm4, ymm4, ymm8 vpsrld ymm8, ymm5, 12 vpslld ymm5, ymm5, 20 vpor ymm5, ymm5, ymm8 vpsrld ymm8, ymm6, 12 vpslld ymm6, ymm6, 20 vpor ymm6, ymm6, ymm8 vpsrld ymm8, ymm7, 12 vpslld ymm7, ymm7, 20 vpor ymm7, ymm7, ymm8 vpaddd ymm0, ymm0, ymmword ptr [rsp+80H] vpaddd ymm1, ymm1, ymmword ptr [rsp+180H] vpaddd ymm2, ymm2, ymmword ptr [rsp+40H] vpaddd ymm3, ymm3, ymmword ptr [rsp+1C0H] vpaddd ymm0, ymm0, ymm4 vpaddd ymm1, ymm1, ymm5 vpaddd ymm2, ymm2, ymm6 vpaddd ymm3, ymm3, ymm7 vpxor ymm12, ymm12, ymm0 vpxor ymm13, ymm13, ymm1 vpxor ymm14, ymm14, ymm2 vpxor ymm15, ymm15, ymm3 vbroadcasti128 ymm8, xmmword ptr [ROT8] vpshufb ymm12, ymm12, ymm8 vpshufb ymm13, ymm13, ymm8 vpshufb ymm14, ymm14, ymm8 vpshufb ymm15, ymm15, ymm8 vpaddd ymm8, ymm12, ymmword ptr [rsp+200H] vpaddd ymm9, ymm9, ymm13 vpaddd ymm10, ymm10, ymm14 vpaddd ymm11, ymm11, ymm15 vpxor ymm4, ymm4, ymm8 vpxor ymm5, ymm5, ymm9 vpxor ymm6, ymm6, ymm10 vpxor ymm7, ymm7, ymm11 vmovdqa ymmword ptr [rsp+200H], ymm8 vpsrld ymm8, ymm4, 7 vpslld ymm4, ymm4, 25 vpor ymm4, ymm4, ymm8 vpsrld ymm8, ymm5, 7 vpslld ymm5, ymm5, 25 vpor ymm5, ymm5, ymm8 vpsrld ymm8, ymm6, 7 vpslld ymm6, ymm6, 25 vpor ymm6, ymm6, ymm8 vpsrld ymm8, ymm7, 7 vpslld ymm7, ymm7, 25 vpor ymm7, ymm7, ymm8 vpaddd ymm0, ymm0, ymmword ptr [rsp+0C0H] vpaddd ymm1, ymm1, ymmword ptr [rsp+120H] vpaddd ymm2, ymm2, ymmword ptr [rsp+160H] vpaddd ymm3, ymm3, ymmword ptr [rsp+100H] vpaddd ymm0, ymm0, ymm5 vpaddd ymm1, ymm1, ymm6 vpaddd ymm2, ymm2, ymm7 vpaddd ymm3, ymm3, ymm4 vpxor ymm15, ymm15, ymm0 vpxor ymm12, ymm12, ymm1 vpxor ymm13, ymm13, ymm2 vpxor ymm14, ymm14, ymm3 vbroadcasti128 ymm8, xmmword ptr [ROT16] vpshufb ymm15, ymm15, ymm8 vpshufb ymm12, ymm12, ymm8 vpshufb ymm13, ymm13, ymm8 vpshufb ymm14, ymm14, ymm8 vpaddd ymm10, ymm10, ymm15 vpaddd ymm11, ymm11, ymm12 vpaddd ymm8, ymm13, ymmword ptr [rsp+200H] vpaddd ymm9, ymm9, ymm14 vpxor ymm5, ymm5, ymm10 vpxor ymm6, ymm6, ymm11 vpxor ymm7, ymm7, ymm8 vpxor ymm4, ymm4, ymm9 vmovdqa ymmword ptr [rsp+200H], ymm8 vpsrld ymm8, ymm5, 12 vpslld ymm5, ymm5, 20 vpor ymm5, ymm5, ymm8 vpsrld ymm8, ymm6, 12 vpslld ymm6, ymm6, 20 vpor ymm6, ymm6, ymm8 vpsrld ymm8, ymm7, 12 vpslld ymm7, ymm7, 20 vpor ymm7, ymm7, ymm8 vpsrld ymm8, ymm4, 12 vpslld ymm4, ymm4, 20 vpor ymm4, ymm4, ymm8 vpaddd ymm0, ymm0, ymmword ptr [rsp+0A0H] vpaddd ymm1, ymm1, ymmword ptr [rsp] vpaddd ymm2, ymm2, ymmword ptr [rsp+1E0H] vpaddd ymm3, ymm3, ymmword ptr [rsp+20H] vpaddd ymm0, ymm0, ymm5 vpaddd ymm1, ymm1, ymm6 vpaddd ymm2, ymm2, ymm7 vpaddd ymm3, ymm3, ymm4 vpxor ymm15, ymm15, ymm0 vpxor ymm12, ymm12, ymm1 vpxor ymm13, ymm13, ymm2 vpxor ymm14, ymm14, ymm3 vbroadcasti128 ymm8, xmmword ptr [ROT8] vpshufb ymm15, ymm15, ymm8 vpshufb ymm12, ymm12, ymm8 vpshufb ymm13, ymm13, ymm8 vpshufb ymm14, ymm14, ymm8 vpaddd ymm10, ymm10, ymm15 vpaddd ymm11, ymm11, ymm12 vpaddd ymm8, ymm13, ymmword ptr [rsp+200H] vpaddd ymm9, ymm9, ymm14 vpxor ymm5, ymm5, ymm10 vpxor ymm6, ymm6, ymm11 vpxor ymm7, ymm7, ymm8 vpxor ymm4, ymm4, ymm9 vmovdqa ymmword ptr [rsp+200H], ymm8 vpsrld ymm8, ymm5, 7 vpslld ymm5, ymm5, 25 vpor ymm5, ymm5, ymm8 vpsrld ymm8, ymm6, 7 vpslld ymm6, ymm6, 25 vpor ymm6, ymm6, ymm8 vpsrld ymm8, ymm7, 7 vpslld ymm7, ymm7, 25 vpor ymm7, ymm7, ymm8 vpsrld ymm8, ymm4, 7 vpslld ymm4, ymm4, 25 vpor ymm4, ymm4, ymm8 vpaddd ymm0, ymm0, ymmword ptr [rsp+140H] vpaddd ymm1, ymm1, ymmword ptr [rsp+180H] vpaddd ymm2, ymm2, ymmword ptr [rsp+1C0H] vpaddd ymm3, ymm3, ymmword ptr [rsp+1A0H] vpaddd ymm0, ymm0, ymm4 vpaddd ymm1, ymm1, ymm5 vpaddd ymm2, ymm2, ymm6 vpaddd ymm3, ymm3, ymm7 vpxor ymm12, ymm12, ymm0 vpxor ymm13, ymm13, ymm1 vpxor ymm14, ymm14, ymm2 vpxor ymm15, ymm15, ymm3 vbroadcasti128 ymm8, xmmword ptr [ROT16] vpshufb ymm12, ymm12, ymm8 vpshufb ymm13, ymm13, ymm8 vpshufb ymm14, ymm14, ymm8 vpshufb ymm15, ymm15, ymm8 vpaddd ymm8, ymm12, ymmword ptr [rsp+200H] vpaddd ymm9, ymm9, ymm13 vpaddd ymm10, ymm10, ymm14 vpaddd ymm11, ymm11, ymm15 vpxor ymm4, ymm4, ymm8 vpxor ymm5, ymm5, ymm9 vpxor ymm6, ymm6, ymm10 vpxor ymm7, ymm7, ymm11 vmovdqa ymmword ptr [rsp+200H], ymm8 vpsrld ymm8, ymm4, 12 vpslld ymm4, ymm4, 20 vpor ymm4, ymm4, ymm8 vpsrld ymm8, ymm5, 12 vpslld ymm5, ymm5, 20 vpor ymm5, ymm5, ymm8 vpsrld ymm8, ymm6, 12 vpslld ymm6, ymm6, 20 vpor ymm6, ymm6, ymm8 vpsrld ymm8, ymm7, 12 vpslld ymm7, ymm7, 20 vpor ymm7, ymm7, ymm8 vpaddd ymm0, ymm0, ymmword ptr [rsp+0E0H] vpaddd ymm1, ymm1, ymmword ptr [rsp+120H] vpaddd ymm2, ymm2, ymmword ptr [rsp+60H] vpaddd ymm3, ymm3, ymmword ptr [rsp+1E0H] vpaddd ymm0, ymm0, ymm4 vpaddd ymm1, ymm1, ymm5 vpaddd ymm2, ymm2, ymm6 vpaddd ymm3, ymm3, ymm7 vpxor ymm12, ymm12, ymm0 vpxor ymm13, ymm13, ymm1 vpxor ymm14, ymm14, ymm2 vpxor ymm15, ymm15, ymm3 vbroadcasti128 ymm8, xmmword ptr [ROT8] vpshufb ymm12, ymm12, ymm8 vpshufb ymm13, ymm13, ymm8 vpshufb ymm14, ymm14, ymm8 vpshufb ymm15, ymm15, ymm8 vpaddd ymm8, ymm12, ymmword ptr [rsp+200H] vpaddd ymm9, ymm9, ymm13 vpaddd ymm10, ymm10, ymm14 vpaddd ymm11, ymm11, ymm15 vpxor ymm4, ymm4, ymm8 vpxor ymm5, ymm5, ymm9 vpxor ymm6, ymm6, ymm10 vpxor ymm7, ymm7, ymm11 vmovdqa ymmword ptr [rsp+200H], ymm8 vpsrld ymm8, ymm4, 7 vpslld ymm4, ymm4, 25 vpor ymm4, ymm4, ymm8 vpsrld ymm8, ymm5, 7 vpslld ymm5, ymm5, 25 vpor ymm5, ymm5, ymm8 vpsrld ymm8, ymm6, 7 vpslld ymm6, ymm6, 25 vpor ymm6, ymm6, ymm8 vpsrld ymm8, ymm7, 7 vpslld ymm7, ymm7, 25 vpor ymm7, ymm7, ymm8 vpaddd ymm0, ymm0, ymmword ptr [rsp+80H] vpaddd ymm1, ymm1, ymmword ptr [rsp+160H] vpaddd ymm2, ymm2, ymmword ptr [rsp+0A0H] vpaddd ymm3, ymm3, ymmword ptr [rsp+20H] vpaddd ymm0, ymm0, ymm5 vpaddd ymm1, ymm1, ymm6 vpaddd ymm2, ymm2, ymm7 vpaddd ymm3, ymm3, ymm4 vpxor ymm15, ymm15, ymm0 vpxor ymm12, ymm12, ymm1 vpxor ymm13, ymm13, ymm2 vpxor ymm14, ymm14, ymm3 vbroadcasti128 ymm8, xmmword ptr [ROT16] vpshufb ymm15, ymm15, ymm8 vpshufb ymm12, ymm12, ymm8 vpshufb ymm13, ymm13, ymm8 vpshufb ymm14, ymm14, ymm8 vpaddd ymm10, ymm10, ymm15 vpaddd ymm11, ymm11, ymm12 vpaddd ymm8, ymm13, ymmword ptr [rsp+200H] vpaddd ymm9, ymm9, ymm14 vpxor ymm5, ymm5, ymm10 vpxor ymm6, ymm6, ymm11 vpxor ymm7, ymm7, ymm8 vpxor ymm4, ymm4, ymm9 vmovdqa ymmword ptr [rsp+200H], ymm8 vpsrld ymm8, ymm5, 12 vpslld ymm5, ymm5, 20 vpor ymm5, ymm5, ymm8 vpsrld ymm8, ymm6, 12 vpslld ymm6, ymm6, 20 vpor ymm6, ymm6, ymm8 vpsrld ymm8, ymm7, 12 vpslld ymm7, ymm7, 20 vpor ymm7, ymm7, ymm8 vpsrld ymm8, ymm4, 12 vpslld ymm4, ymm4, 20 vpor ymm4, ymm4, ymm8 vpaddd ymm0, ymm0, ymmword ptr [rsp] vpaddd ymm1, ymm1, ymmword ptr [rsp+40H] vpaddd ymm2, ymm2, ymmword ptr [rsp+100H] vpaddd ymm3, ymm3, ymmword ptr [rsp+0C0H] vpaddd ymm0, ymm0, ymm5 vpaddd ymm1, ymm1, ymm6 vpaddd ymm2, ymm2, ymm7 vpaddd ymm3, ymm3, ymm4 vpxor ymm15, ymm15, ymm0 vpxor ymm12, ymm12, ymm1 vpxor ymm13, ymm13, ymm2 vpxor ymm14, ymm14, ymm3 vbroadcasti128 ymm8, xmmword ptr [ROT8] vpshufb ymm15, ymm15, ymm8 vpshufb ymm12, ymm12, ymm8 vpshufb ymm13, ymm13, ymm8 vpshufb ymm14, ymm14, ymm8 vpaddd ymm10, ymm10, ymm15 vpaddd ymm11, ymm11, ymm12 vpaddd ymm8, ymm13, ymmword ptr [rsp+200H] vpaddd ymm9, ymm9, ymm14 vpxor ymm5, ymm5, ymm10 vpxor ymm6, ymm6, ymm11 vpxor ymm7, ymm7, ymm8 vpxor ymm4, ymm4, ymm9 vmovdqa ymmword ptr [rsp+200H], ymm8 vpsrld ymm8, ymm5, 7 vpslld ymm5, ymm5, 25 vpor ymm5, ymm5, ymm8 vpsrld ymm8, ymm6, 7 vpslld ymm6, ymm6, 25 vpor ymm6, ymm6, ymm8 vpsrld ymm8, ymm7, 7 vpslld ymm7, ymm7, 25 vpor ymm7, ymm7, ymm8 vpsrld ymm8, ymm4, 7 vpslld ymm4, ymm4, 25 vpor ymm4, ymm4, ymm8 vpaddd ymm0, ymm0, ymmword ptr [rsp+180H] vpaddd ymm1, ymm1, ymmword ptr [rsp+120H] vpaddd ymm2, ymm2, ymmword ptr [rsp+1E0H] vpaddd ymm3, ymm3, ymmword ptr [rsp+1C0H] vpaddd ymm0, ymm0, ymm4 vpaddd ymm1, ymm1, ymm5 vpaddd ymm2, ymm2, ymm6 vpaddd ymm3, ymm3, ymm7 vpxor ymm12, ymm12, ymm0 vpxor ymm13, ymm13, ymm1 vpxor ymm14, ymm14, ymm2 vpxor ymm15, ymm15, ymm3 vbroadcasti128 ymm8, xmmword ptr [ROT16] vpshufb ymm12, ymm12, ymm8 vpshufb ymm13, ymm13, ymm8 vpshufb ymm14, ymm14, ymm8 vpshufb ymm15, ymm15, ymm8 vpaddd ymm8, ymm12, ymmword ptr [rsp+200H] vpaddd ymm9, ymm9, ymm13 vpaddd ymm10, ymm10, ymm14 vpaddd ymm11, ymm11, ymm15 vpxor ymm4, ymm4, ymm8 vpxor ymm5, ymm5, ymm9 vpxor ymm6, ymm6, ymm10 vpxor ymm7, ymm7, ymm11 vmovdqa ymmword ptr [rsp+200H], ymm8 vpsrld ymm8, ymm4, 12 vpslld ymm4, ymm4, 20 vpor ymm4, ymm4, ymm8 vpsrld ymm8, ymm5, 12 vpslld ymm5, ymm5, 20 vpor ymm5, ymm5, ymm8 vpsrld ymm8, ymm6, 12 vpslld ymm6, ymm6, 20 vpor ymm6, ymm6, ymm8 vpsrld ymm8, ymm7, 12 vpslld ymm7, ymm7, 20 vpor ymm7, ymm7, ymm8 vpaddd ymm0, ymm0, ymmword ptr [rsp+1A0H] vpaddd ymm1, ymm1, ymmword ptr [rsp+160H] vpaddd ymm2, ymm2, ymmword ptr [rsp+140H] vpaddd ymm3, ymm3, ymmword ptr [rsp+100H] vpaddd ymm0, ymm0, ymm4 vpaddd ymm1, ymm1, ymm5 vpaddd ymm2, ymm2, ymm6 vpaddd ymm3, ymm3, ymm7 vpxor ymm12, ymm12, ymm0 vpxor ymm13, ymm13, ymm1 vpxor ymm14, ymm14, ymm2 vpxor ymm15, ymm15, ymm3 vbroadcasti128 ymm8, xmmword ptr [ROT8] vpshufb ymm12, ymm12, ymm8 vpshufb ymm13, ymm13, ymm8 vpshufb ymm14, ymm14, ymm8 vpshufb ymm15, ymm15, ymm8 vpaddd ymm8, ymm12, ymmword ptr [rsp+200H] vpaddd ymm9, ymm9, ymm13 vpaddd ymm10, ymm10, ymm14 vpaddd ymm11, ymm11, ymm15 vpxor ymm4, ymm4, ymm8 vpxor ymm5, ymm5, ymm9 vpxor ymm6, ymm6, ymm10 vpxor ymm7, ymm7, ymm11 vmovdqa ymmword ptr [rsp+200H], ymm8 vpsrld ymm8, ymm4, 7 vpslld ymm4, ymm4, 25 vpor ymm4, ymm4, ymm8 vpsrld ymm8, ymm5, 7 vpslld ymm5, ymm5, 25 vpor ymm5, ymm5, ymm8 vpsrld ymm8, ymm6, 7 vpslld ymm6, ymm6, 25 vpor ymm6, ymm6, ymm8 vpsrld ymm8, ymm7, 7 vpslld ymm7, ymm7, 25 vpor ymm7, ymm7, ymm8 vpaddd ymm0, ymm0, ymmword ptr [rsp+0E0H] vpaddd ymm1, ymm1, ymmword ptr [rsp+0A0H] vpaddd ymm2, ymm2, ymmword ptr [rsp] vpaddd ymm3, ymm3, ymmword ptr [rsp+0C0H] vpaddd ymm0, ymm0, ymm5 vpaddd ymm1, ymm1, ymm6 vpaddd ymm2, ymm2, ymm7 vpaddd ymm3, ymm3, ymm4 vpxor ymm15, ymm15, ymm0 vpxor ymm12, ymm12, ymm1 vpxor ymm13, ymm13, ymm2 vpxor ymm14, ymm14, ymm3 vbroadcasti128 ymm8, xmmword ptr [ROT16] vpshufb ymm15, ymm15, ymm8 vpshufb ymm12, ymm12, ymm8 vpshufb ymm13, ymm13, ymm8 vpshufb ymm14, ymm14, ymm8 vpaddd ymm10, ymm10, ymm15 vpaddd ymm11, ymm11, ymm12 vpaddd ymm8, ymm13, ymmword ptr [rsp+200H] vpaddd ymm9, ymm9, ymm14 vpxor ymm5, ymm5, ymm10 vpxor ymm6, ymm6, ymm11 vpxor ymm7, ymm7, ymm8 vpxor ymm4, ymm4, ymm9 vmovdqa ymmword ptr [rsp+200H], ymm8 vpsrld ymm8, ymm5, 12 vpslld ymm5, ymm5, 20 vpor ymm5, ymm5, ymm8 vpsrld ymm8, ymm6, 12 vpslld ymm6, ymm6, 20 vpor ymm6, ymm6, ymm8 vpsrld ymm8, ymm7, 12 vpslld ymm7, ymm7, 20 vpor ymm7, ymm7, ymm8 vpsrld ymm8, ymm4, 12 vpslld ymm4, ymm4, 20 vpor ymm4, ymm4, ymm8 vpaddd ymm0, ymm0, ymmword ptr [rsp+40H] vpaddd ymm1, ymm1, ymmword ptr [rsp+60H] vpaddd ymm2, ymm2, ymmword ptr [rsp+20H] vpaddd ymm3, ymm3, ymmword ptr [rsp+80H] vpaddd ymm0, ymm0, ymm5 vpaddd ymm1, ymm1, ymm6 vpaddd ymm2, ymm2, ymm7 vpaddd ymm3, ymm3, ymm4 vpxor ymm15, ymm15, ymm0 vpxor ymm12, ymm12, ymm1 vpxor ymm13, ymm13, ymm2 vpxor ymm14, ymm14, ymm3 vbroadcasti128 ymm8, xmmword ptr [ROT8] vpshufb ymm15, ymm15, ymm8 vpshufb ymm12, ymm12, ymm8 vpshufb ymm13, ymm13, ymm8 vpshufb ymm14, ymm14, ymm8 vpaddd ymm10, ymm10, ymm15 vpaddd ymm11, ymm11, ymm12 vpaddd ymm8, ymm13, ymmword ptr [rsp+200H] vpaddd ymm9, ymm9, ymm14 vpxor ymm5, ymm5, ymm10 vpxor ymm6, ymm6, ymm11 vpxor ymm7, ymm7, ymm8 vpxor ymm4, ymm4, ymm9 vmovdqa ymmword ptr [rsp+200H], ymm8 vpsrld ymm8, ymm5, 7 vpslld ymm5, ymm5, 25 vpor ymm5, ymm5, ymm8 vpsrld ymm8, ymm6, 7 vpslld ymm6, ymm6, 25 vpor ymm6, ymm6, ymm8 vpsrld ymm8, ymm7, 7 vpslld ymm7, ymm7, 25 vpor ymm7, ymm7, ymm8 vpsrld ymm8, ymm4, 7 vpslld ymm4, ymm4, 25 vpor ymm4, ymm4, ymm8 vpaddd ymm0, ymm0, ymmword ptr [rsp+120H] vpaddd ymm1, ymm1, ymmword ptr [rsp+160H] vpaddd ymm2, ymm2, ymmword ptr [rsp+100H] vpaddd ymm3, ymm3, ymmword ptr [rsp+1E0H] vpaddd ymm0, ymm0, ymm4 vpaddd ymm1, ymm1, ymm5 vpaddd ymm2, ymm2, ymm6 vpaddd ymm3, ymm3, ymm7 vpxor ymm12, ymm12, ymm0 vpxor ymm13, ymm13, ymm1 vpxor ymm14, ymm14, ymm2 vpxor ymm15, ymm15, ymm3 vbroadcasti128 ymm8, xmmword ptr [ROT16] vpshufb ymm12, ymm12, ymm8 vpshufb ymm13, ymm13, ymm8 vpshufb ymm14, ymm14, ymm8 vpshufb ymm15, ymm15, ymm8 vpaddd ymm8, ymm12, ymmword ptr [rsp+200H] vpaddd ymm9, ymm9, ymm13 vpaddd ymm10, ymm10, ymm14 vpaddd ymm11, ymm11, ymm15 vpxor ymm4, ymm4, ymm8 vpxor ymm5, ymm5, ymm9 vpxor ymm6, ymm6, ymm10 vpxor ymm7, ymm7, ymm11 vmovdqa ymmword ptr [rsp+200H], ymm8 vpsrld ymm8, ymm4, 12 vpslld ymm4, ymm4, 20 vpor ymm4, ymm4, ymm8 vpsrld ymm8, ymm5, 12 vpslld ymm5, ymm5, 20 vpor ymm5, ymm5, ymm8 vpsrld ymm8, ymm6, 12 vpslld ymm6, ymm6, 20 vpor ymm6, ymm6, ymm8 vpsrld ymm8, ymm7, 12 vpslld ymm7, ymm7, 20 vpor ymm7, ymm7, ymm8 vpaddd ymm0, ymm0, ymmword ptr [rsp+1C0H] vpaddd ymm1, ymm1, ymmword ptr [rsp+0A0H] vpaddd ymm2, ymm2, ymmword ptr [rsp+180H] vpaddd ymm3, ymm3, ymmword ptr [rsp+20H] vpaddd ymm0, ymm0, ymm4 vpaddd ymm1, ymm1, ymm5 vpaddd ymm2, ymm2, ymm6 vpaddd ymm3, ymm3, ymm7 vpxor ymm12, ymm12, ymm0 vpxor ymm13, ymm13, ymm1 vpxor ymm14, ymm14, ymm2 vpxor ymm15, ymm15, ymm3 vbroadcasti128 ymm8, xmmword ptr [ROT8] vpshufb ymm12, ymm12, ymm8 vpshufb ymm13, ymm13, ymm8 vpshufb ymm14, ymm14, ymm8 vpshufb ymm15, ymm15, ymm8 vpaddd ymm8, ymm12, ymmword ptr [rsp+200H] vpaddd ymm9, ymm9, ymm13 vpaddd ymm10, ymm10, ymm14 vpaddd ymm11, ymm11, ymm15 vpxor ymm4, ymm4, ymm8 vpxor ymm5, ymm5, ymm9 vpxor ymm6, ymm6, ymm10 vpxor ymm7, ymm7, ymm11 vmovdqa ymmword ptr [rsp+200H], ymm8 vpsrld ymm8, ymm4, 7 vpslld ymm4, ymm4, 25 vpor ymm4, ymm4, ymm8 vpsrld ymm8, ymm5, 7 vpslld ymm5, ymm5, 25 vpor ymm5, ymm5, ymm8 vpsrld ymm8, ymm6, 7 vpslld ymm6, ymm6, 25 vpor ymm6, ymm6, ymm8 vpsrld ymm8, ymm7, 7 vpslld ymm7, ymm7, 25 vpor ymm7, ymm7, ymm8 vpaddd ymm0, ymm0, ymmword ptr [rsp+1A0H] vpaddd ymm1, ymm1, ymmword ptr [rsp] vpaddd ymm2, ymm2, ymmword ptr [rsp+40H] vpaddd ymm3, ymm3, ymmword ptr [rsp+80H] vpaddd ymm0, ymm0, ymm5 vpaddd ymm1, ymm1, ymm6 vpaddd ymm2, ymm2, ymm7 vpaddd ymm3, ymm3, ymm4 vpxor ymm15, ymm15, ymm0 vpxor ymm12, ymm12, ymm1 vpxor ymm13, ymm13, ymm2 vpxor ymm14, ymm14, ymm3 vbroadcasti128 ymm8, xmmword ptr [ROT16] vpshufb ymm15, ymm15, ymm8 vpshufb ymm12, ymm12, ymm8 vpshufb ymm13, ymm13, ymm8 vpshufb ymm14, ymm14, ymm8 vpaddd ymm10, ymm10, ymm15 vpaddd ymm11, ymm11, ymm12 vpaddd ymm8, ymm13, ymmword ptr [rsp+200H] vpaddd ymm9, ymm9, ymm14 vpxor ymm5, ymm5, ymm10 vpxor ymm6, ymm6, ymm11 vpxor ymm7, ymm7, ymm8 vpxor ymm4, ymm4, ymm9 vmovdqa ymmword ptr [rsp+200H], ymm8 vpsrld ymm8, ymm5, 12 vpslld ymm5, ymm5, 20 vpor ymm5, ymm5, ymm8 vpsrld ymm8, ymm6, 12 vpslld ymm6, ymm6, 20 vpor ymm6, ymm6, ymm8 vpsrld ymm8, ymm7, 12 vpslld ymm7, ymm7, 20 vpor ymm7, ymm7, ymm8 vpsrld ymm8, ymm4, 12 vpslld ymm4, ymm4, 20 vpor ymm4, ymm4, ymm8 vpaddd ymm0, ymm0, ymmword ptr [rsp+60H] vpaddd ymm1, ymm1, ymmword ptr [rsp+140H] vpaddd ymm2, ymm2, ymmword ptr [rsp+0C0H] vpaddd ymm3, ymm3, ymmword ptr [rsp+0E0H] vpaddd ymm0, ymm0, ymm5 vpaddd ymm1, ymm1, ymm6 vpaddd ymm2, ymm2, ymm7 vpaddd ymm3, ymm3, ymm4 vpxor ymm15, ymm15, ymm0 vpxor ymm12, ymm12, ymm1 vpxor ymm13, ymm13, ymm2 vpxor ymm14, ymm14, ymm3 vbroadcasti128 ymm8, xmmword ptr [ROT8] vpshufb ymm15, ymm15, ymm8 vpshufb ymm12, ymm12, ymm8 vpshufb ymm13, ymm13, ymm8 vpshufb ymm14, ymm14, ymm8 vpaddd ymm10, ymm10, ymm15 vpaddd ymm11, ymm11, ymm12 vpaddd ymm8, ymm13, ymmword ptr [rsp+200H] vpaddd ymm9, ymm9, ymm14 vpxor ymm5, ymm5, ymm10 vpxor ymm6, ymm6, ymm11 vpxor ymm7, ymm7, ymm8 vpxor ymm4, ymm4, ymm9 vmovdqa ymmword ptr [rsp+200H], ymm8 vpsrld ymm8, ymm5, 7 vpslld ymm5, ymm5, 25 vpor ymm5, ymm5, ymm8 vpsrld ymm8, ymm6, 7 vpslld ymm6, ymm6, 25 vpor ymm6, ymm6, ymm8 vpsrld ymm8, ymm7, 7 vpslld ymm7, ymm7, 25 vpor ymm7, ymm7, ymm8 vpsrld ymm8, ymm4, 7 vpslld ymm4, ymm4, 25 vpor ymm4, ymm4, ymm8 vpaddd ymm0, ymm0, ymmword ptr [rsp+160H] vpaddd ymm1, ymm1, ymmword ptr [rsp+0A0H] vpaddd ymm2, ymm2, ymmword ptr [rsp+20H] vpaddd ymm3, ymm3, ymmword ptr [rsp+100H] vpaddd ymm0, ymm0, ymm4 vpaddd ymm1, ymm1, ymm5 vpaddd ymm2, ymm2, ymm6 vpaddd ymm3, ymm3, ymm7 vpxor ymm12, ymm12, ymm0 vpxor ymm13, ymm13, ymm1 vpxor ymm14, ymm14, ymm2 vpxor ymm15, ymm15, ymm3 vbroadcasti128 ymm8, xmmword ptr [ROT16] vpshufb ymm12, ymm12, ymm8 vpshufb ymm13, ymm13, ymm8 vpshufb ymm14, ymm14, ymm8 vpshufb ymm15, ymm15, ymm8 vpaddd ymm8, ymm12, ymmword ptr [rsp+200H] vpaddd ymm9, ymm9, ymm13 vpaddd ymm10, ymm10, ymm14 vpaddd ymm11, ymm11, ymm15 vpxor ymm4, ymm4, ymm8 vpxor ymm5, ymm5, ymm9 vpxor ymm6, ymm6, ymm10 vpxor ymm7, ymm7, ymm11 vmovdqa ymmword ptr [rsp+200H], ymm8 vpsrld ymm8, ymm4, 12 vpslld ymm4, ymm4, 20 vpor ymm4, ymm4, ymm8 vpsrld ymm8, ymm5, 12 vpslld ymm5, ymm5, 20 vpor ymm5, ymm5, ymm8 vpsrld ymm8, ymm6, 12 vpslld ymm6, ymm6, 20 vpor ymm6, ymm6, ymm8 vpsrld ymm8, ymm7, 12 vpslld ymm7, ymm7, 20 vpor ymm7, ymm7, ymm8 vpaddd ymm0, ymm0, ymmword ptr [rsp+1E0H] vpaddd ymm1, ymm1, ymmword ptr [rsp] vpaddd ymm2, ymm2, ymmword ptr [rsp+120H] vpaddd ymm3, ymm3, ymmword ptr [rsp+0C0H] vpaddd ymm0, ymm0, ymm4 vpaddd ymm1, ymm1, ymm5 vpaddd ymm2, ymm2, ymm6 vpaddd ymm3, ymm3, ymm7 vpxor ymm12, ymm12, ymm0 vpxor ymm13, ymm13, ymm1 vpxor ymm14, ymm14, ymm2 vpxor ymm15, ymm15, ymm3 vbroadcasti128 ymm8, xmmword ptr [ROT8] vpshufb ymm12, ymm12, ymm8 vpshufb ymm13, ymm13, ymm8 vpshufb ymm14, ymm14, ymm8 vpshufb ymm15, ymm15, ymm8 vpaddd ymm8, ymm12, ymmword ptr [rsp+200H] vpaddd ymm9, ymm9, ymm13 vpaddd ymm10, ymm10, ymm14 vpaddd ymm11, ymm11, ymm15 vpxor ymm4, ymm4, ymm8 vpxor ymm5, ymm5, ymm9 vpxor ymm6, ymm6, ymm10 vpxor ymm7, ymm7, ymm11 vmovdqa ymmword ptr [rsp+200H], ymm8 vpsrld ymm8, ymm4, 7 vpslld ymm4, ymm4, 25 vpor ymm4, ymm4, ymm8 vpsrld ymm8, ymm5, 7 vpslld ymm5, ymm5, 25 vpor ymm5, ymm5, ymm8 vpsrld ymm8, ymm6, 7 vpslld ymm6, ymm6, 25 vpor ymm6, ymm6, ymm8 vpsrld ymm8, ymm7, 7 vpslld ymm7, ymm7, 25 vpor ymm7, ymm7, ymm8 vpaddd ymm0, ymm0, ymmword ptr [rsp+1C0H] vpaddd ymm1, ymm1, ymmword ptr [rsp+40H] vpaddd ymm2, ymm2, ymmword ptr [rsp+60H] vpaddd ymm3, ymm3, ymmword ptr [rsp+0E0H] vpaddd ymm0, ymm0, ymm5 vpaddd ymm1, ymm1, ymm6 vpaddd ymm2, ymm2, ymm7 vpaddd ymm3, ymm3, ymm4 vpxor ymm15, ymm15, ymm0 vpxor ymm12, ymm12, ymm1 vpxor ymm13, ymm13, ymm2 vpxor ymm14, ymm14, ymm3 vbroadcasti128 ymm8, xmmword ptr [ROT16] vpshufb ymm15, ymm15, ymm8 vpshufb ymm12, ymm12, ymm8 vpshufb ymm13, ymm13, ymm8 vpshufb ymm14, ymm14, ymm8 vpaddd ymm10, ymm10, ymm15 vpaddd ymm11, ymm11, ymm12 vpaddd ymm8, ymm13, ymmword ptr [rsp+200H] vpaddd ymm9, ymm9, ymm14 vpxor ymm5, ymm5, ymm10 vpxor ymm6, ymm6, ymm11 vpxor ymm7, ymm7, ymm8 vpxor ymm4, ymm4, ymm9 vmovdqa ymmword ptr [rsp+200H], ymm8 vpsrld ymm8, ymm5, 12 vpslld ymm5, ymm5, 20 vpor ymm5, ymm5, ymm8 vpsrld ymm8, ymm6, 12 vpslld ymm6, ymm6, 20 vpor ymm6, ymm6, ymm8 vpsrld ymm8, ymm7, 12 vpslld ymm7, ymm7, 20 vpor ymm7, ymm7, ymm8 vpsrld ymm8, ymm4, 12 vpslld ymm4, ymm4, 20 vpor ymm4, ymm4, ymm8 vpaddd ymm0, ymm0, ymmword ptr [rsp+140H] vpaddd ymm1, ymm1, ymmword ptr [rsp+180H] vpaddd ymm2, ymm2, ymmword ptr [rsp+80H] vpaddd ymm3, ymm3, ymmword ptr [rsp+1A0H] vpaddd ymm0, ymm0, ymm5 vpaddd ymm1, ymm1, ymm6 vpaddd ymm2, ymm2, ymm7 vpaddd ymm3, ymm3, ymm4 vpxor ymm15, ymm15, ymm0 vpxor ymm12, ymm12, ymm1 vpxor ymm13, ymm13, ymm2 vpxor ymm14, ymm14, ymm3 vbroadcasti128 ymm8, xmmword ptr [ROT8] vpshufb ymm15, ymm15, ymm8 vpshufb ymm12, ymm12, ymm8 vpshufb ymm13, ymm13, ymm8 vpshufb ymm14, ymm14, ymm8 vpaddd ymm10, ymm10, ymm15 vpaddd ymm11, ymm11, ymm12 vpaddd ymm8, ymm13, ymmword ptr [rsp+200H] vpaddd ymm9, ymm9, ymm14 vpxor ymm5, ymm5, ymm10 vpxor ymm6, ymm6, ymm11 vpxor ymm7, ymm7, ymm8 vpxor ymm4, ymm4, ymm9 vpxor ymm0, ymm0, ymm8 vpxor ymm1, ymm1, ymm9 vpxor ymm2, ymm2, ymm10 vpxor ymm3, ymm3, ymm11 vpsrld ymm8, ymm5, 7 vpslld ymm5, ymm5, 25 vpor ymm5, ymm5, ymm8 vpsrld ymm8, ymm6, 7 vpslld ymm6, ymm6, 25 vpor ymm6, ymm6, ymm8 vpsrld ymm8, ymm7, 7 vpslld ymm7, ymm7, 25 vpor ymm7, ymm7, ymm8 vpsrld ymm8, ymm4, 7 vpslld ymm4, ymm4, 25 vpor ymm4, ymm4, ymm8 vpxor ymm4, ymm4, ymm12 vpxor ymm5, ymm5, ymm13 vpxor ymm6, ymm6, ymm14 vpxor ymm7, ymm7, ymm15 movzx eax, byte ptr [rbp+78H] jne innerloop8 mov rbx, qword ptr [rbp+90H] vunpcklps ymm8, ymm0, ymm1 vunpcklps ymm9, ymm2, ymm3 vunpckhps ymm10, ymm0, ymm1 vunpcklps ymm11, ymm4, ymm5 vunpcklps ymm0, ymm6, ymm7 vshufps ymm12, ymm8, ymm9, 78 vblendps ymm1, ymm8, ymm12, 0CCH vshufps ymm8, ymm11, ymm0, 78 vunpckhps ymm13, ymm2, ymm3 vblendps ymm2, ymm11, ymm8, 0CCH vblendps ymm3, ymm12, ymm9, 0CCH vperm2f128 ymm12, ymm1, ymm2, 20H vmovups ymmword ptr [rbx], ymm12 vunpckhps ymm14, ymm4, ymm5 vblendps ymm4, ymm8, ymm0, 0CCH vunpckhps ymm15, ymm6, ymm7 vperm2f128 ymm7, ymm3, ymm4, 20H vmovups ymmword ptr [rbx+20H], ymm7 vshufps ymm5, ymm10, ymm13, 78 vblendps ymm6, ymm5, ymm13, 0CCH vshufps ymm13, ymm14, ymm15, 78 vblendps ymm10, ymm10, ymm5, 0CCH vblendps ymm14, ymm14, ymm13, 0CCH vperm2f128 ymm8, ymm10, ymm14, 20H vmovups ymmword ptr [rbx+40H], ymm8 vblendps ymm15, ymm13, ymm15, 0CCH vperm2f128 ymm13, ymm6, ymm15, 20H vmovups ymmword ptr [rbx+60H], ymm13 vperm2f128 ymm9, ymm1, ymm2, 31H vperm2f128 ymm11, ymm3, ymm4, 31H vmovups ymmword ptr [rbx+80H], ymm9 vperm2f128 ymm14, ymm10, ymm14, 31H vperm2f128 ymm15, ymm6, ymm15, 31H vmovups ymmword ptr [rbx+0A0H], ymm11 vmovups ymmword ptr [rbx+0C0H], ymm14 vmovups ymmword ptr [rbx+0E0H], ymm15 vmovdqa ymm0, ymmword ptr [rsp+2A0H] vpaddd ymm1, ymm0, ymmword ptr [rsp+220H] vmovdqa ymmword ptr [rsp+220H], ymm1 vpxor ymm0, ymm0, ymmword ptr [CMP_MSB_MASK] vpxor ymm2, ymm1, ymmword ptr [CMP_MSB_MASK] vpcmpgtd ymm2, ymm0, ymm2 vmovdqa ymm0, ymmword ptr [rsp+240H] vpsubd ymm2, ymm0, ymm2 vmovdqa ymmword ptr [rsp+240H], ymm2 add rdi, 64 add rbx, 256 mov qword ptr [rbp+90H], rbx sub rsi, 8 cmp rsi, 8 jnc outerloop8 test rsi, rsi jnz final7blocks unwind: vzeroupper vmovdqa xmm6, xmmword ptr [rsp+2D0H] vmovdqa xmm7, xmmword ptr [rsp+2E0H] vmovdqa xmm8, xmmword ptr [rsp+2F0H] vmovdqa xmm9, xmmword ptr [rsp+300H] vmovdqa xmm10, xmmword ptr [rsp+310H] vmovdqa xmm11, xmmword ptr [rsp+320H] vmovdqa xmm12, xmmword ptr [rsp+330H] vmovdqa xmm13, xmmword ptr [rsp+340H] vmovdqa xmm14, xmmword ptr [rsp+350H] vmovdqa xmm15, xmmword ptr [rsp+360H] mov rsp, rbp pop rbp pop rbx pop rdi pop rsi pop r12 pop r13 pop r14 pop r15 ret ALIGN 16 final7blocks: mov rbx, qword ptr [rbp+90H] mov r15, qword ptr [rsp+2C0H] movzx r13d, byte ptr [rbp+78H] movzx r12d, byte ptr [rbp+88H] test rsi, 4H je final3blocks vbroadcasti128 ymm0, xmmword ptr [rcx] vbroadcasti128 ymm1, xmmword ptr [rcx+10H] vmovdqa ymm8, ymm0 vmovdqa ymm9, ymm1 vbroadcasti128 ymm12, xmmword ptr [rsp+220H] vbroadcasti128 ymm13, xmmword ptr [rsp+240H] vpunpckldq ymm14, ymm12, ymm13 vpunpckhdq ymm15, ymm12, ymm13 vpermq ymm14, ymm14, 50H vpermq ymm15, ymm15, 50H vbroadcasti128 ymm12, xmmword ptr [BLAKE3_BLOCK_LEN] vpblendd ymm14, ymm14, ymm12, 44H vpblendd ymm15, ymm15, ymm12, 44H vmovdqa ymmword ptr [rsp], ymm14 vmovdqa ymmword ptr [rsp+20H], ymm15 mov r8, qword ptr [rdi] mov r9, qword ptr [rdi+8H] mov r10, qword ptr [rdi+10H] mov r11, qword ptr [rdi+18H] movzx eax, byte ptr [rbp+80H] or eax, r13d xor edx, edx ALIGN 16 innerloop4: mov r14d, eax or eax, r12d add rdx, 64 cmp rdx, r15 cmovne eax, r14d mov dword ptr [rsp+200H], eax vmovups ymm2, ymmword ptr [r8+rdx-40H] vinsertf128 ymm2, ymm2, xmmword ptr [r9+rdx-40H], 01H vmovups ymm3, ymmword ptr [r8+rdx-30H] vinsertf128 ymm3, ymm3, xmmword ptr [r9+rdx-30H], 01H vshufps ymm4, ymm2, ymm3, 136 vshufps ymm5, ymm2, ymm3, 221 vmovups ymm2, ymmword ptr [r8+rdx-20H] vinsertf128 ymm2, ymm2, xmmword ptr [r9+rdx-20H], 01H vmovups ymm3, ymmword ptr [r8+rdx-10H] vinsertf128 ymm3, ymm3, xmmword ptr [r9+rdx-10H], 01H vshufps ymm6, ymm2, ymm3, 136 vshufps ymm7, ymm2, ymm3, 221 vpshufd ymm6, ymm6, 93H vpshufd ymm7, ymm7, 93H vmovups ymm10, ymmword ptr [r10+rdx-40H] vinsertf128 ymm10, ymm10, xmmword ptr [r11+rdx-40H], 01H vmovups ymm11, ymmword ptr [r10+rdx-30H] vinsertf128 ymm11, ymm11, xmmword ptr [r11+rdx-30H], 01H vshufps ymm12, ymm10, ymm11, 136 vshufps ymm13, ymm10, ymm11, 221 vmovups ymm10, ymmword ptr [r10+rdx-20H] vinsertf128 ymm10, ymm10, xmmword ptr [r11+rdx-20H], 01H vmovups ymm11, ymmword ptr [r10+rdx-10H] vinsertf128 ymm11, ymm11, xmmword ptr [r11+rdx-10H], 01H vshufps ymm14, ymm10, ymm11, 136 vshufps ymm15, ymm10, ymm11, 221 vpshufd ymm14, ymm14, 93H vpshufd ymm15, ymm15, 93H vpbroadcastd ymm2, dword ptr [rsp+200H] vmovdqa ymm3, ymmword ptr [rsp] vmovdqa ymm11, ymmword ptr [rsp+20H] vpblendd ymm3, ymm3, ymm2, 88H vpblendd ymm11, ymm11, ymm2, 88H vbroadcasti128 ymm2, xmmword ptr [BLAKE3_IV] vmovdqa ymm10, ymm2 mov al, 7 roundloop4: vpaddd ymm0, ymm0, ymm4 vpaddd ymm8, ymm8, ymm12 vmovdqa ymmword ptr [rsp+40H], ymm4 nop vmovdqa ymmword ptr [rsp+60H], ymm12 nop vpaddd ymm0, ymm0, ymm1 vpaddd ymm8, ymm8, ymm9 vpxor ymm3, ymm3, ymm0 vpxor ymm11, ymm11, ymm8 vbroadcasti128 ymm4, xmmword ptr [ROT16] vpshufb ymm3, ymm3, ymm4 vpshufb ymm11, ymm11, ymm4 vpaddd ymm2, ymm2, ymm3 vpaddd ymm10, ymm10, ymm11 vpxor ymm1, ymm1, ymm2 vpxor ymm9, ymm9, ymm10 vpsrld ymm4, ymm1, 12 vpslld ymm1, ymm1, 20 vpor ymm1, ymm1, ymm4 vpsrld ymm4, ymm9, 12 vpslld ymm9, ymm9, 20 vpor ymm9, ymm9, ymm4 vpaddd ymm0, ymm0, ymm5 vpaddd ymm8, ymm8, ymm13 vpaddd ymm0, ymm0, ymm1 vpaddd ymm8, ymm8, ymm9 vmovdqa ymmword ptr [rsp+80H], ymm5 vmovdqa ymmword ptr [rsp+0A0H], ymm13 vpxor ymm3, ymm3, ymm0 vpxor ymm11, ymm11, ymm8 vbroadcasti128 ymm4, xmmword ptr [ROT8] vpshufb ymm3, ymm3, ymm4 vpshufb ymm11, ymm11, ymm4 vpaddd ymm2, ymm2, ymm3 vpaddd ymm10, ymm10, ymm11 vpxor ymm1, ymm1, ymm2 vpxor ymm9, ymm9, ymm10 vpsrld ymm4, ymm1, 7 vpslld ymm1, ymm1, 25 vpor ymm1, ymm1, ymm4 vpsrld ymm4, ymm9, 7 vpslld ymm9, ymm9, 25 vpor ymm9, ymm9, ymm4 vpshufd ymm0, ymm0, 93H vpshufd ymm8, ymm8, 93H vpshufd ymm3, ymm3, 4EH vpshufd ymm11, ymm11, 4EH vpshufd ymm2, ymm2, 39H vpshufd ymm10, ymm10, 39H vpaddd ymm0, ymm0, ymm6 vpaddd ymm8, ymm8, ymm14 vpaddd ymm0, ymm0, ymm1 vpaddd ymm8, ymm8, ymm9 vpxor ymm3, ymm3, ymm0 vpxor ymm11, ymm11, ymm8 vbroadcasti128 ymm4, xmmword ptr [ROT16] vpshufb ymm3, ymm3, ymm4 vpshufb ymm11, ymm11, ymm4 vpaddd ymm2, ymm2, ymm3 vpaddd ymm10, ymm10, ymm11 vpxor ymm1, ymm1, ymm2 vpxor ymm9, ymm9, ymm10 vpsrld ymm4, ymm1, 12 vpslld ymm1, ymm1, 20 vpor ymm1, ymm1, ymm4 vpsrld ymm4, ymm9, 12 vpslld ymm9, ymm9, 20 vpor ymm9, ymm9, ymm4 vpaddd ymm0, ymm0, ymm7 vpaddd ymm8, ymm8, ymm15 vpaddd ymm0, ymm0, ymm1 vpaddd ymm8, ymm8, ymm9 vpxor ymm3, ymm3, ymm0 vpxor ymm11, ymm11, ymm8 vbroadcasti128 ymm4, xmmword ptr [ROT8] vpshufb ymm3, ymm3, ymm4 vpshufb ymm11, ymm11, ymm4 vpaddd ymm2, ymm2, ymm3 vpaddd ymm10, ymm10, ymm11 vpxor ymm1, ymm1, ymm2 vpxor ymm9, ymm9, ymm10 vpsrld ymm4, ymm1, 7 vpslld ymm1, ymm1, 25 vpor ymm1, ymm1, ymm4 vpsrld ymm4, ymm9, 7 vpslld ymm9, ymm9, 25 vpor ymm9, ymm9, ymm4 vpshufd ymm0, ymm0, 39H vpshufd ymm8, ymm8, 39H vpshufd ymm3, ymm3, 4EH vpshufd ymm11, ymm11, 4EH vpshufd ymm2, ymm2, 93H vpshufd ymm10, ymm10, 93H dec al je endroundloop4 vmovdqa ymm4, ymmword ptr [rsp+40H] vmovdqa ymm5, ymmword ptr [rsp+80H] vshufps ymm12, ymm4, ymm5, 214 vpshufd ymm13, ymm4, 0FH vpshufd ymm4, ymm12, 39H vshufps ymm12, ymm6, ymm7, 250 vpblendd ymm13, ymm13, ymm12, 0AAH vpunpcklqdq ymm12, ymm7, ymm5 vpblendd ymm12, ymm12, ymm6, 88H vpshufd ymm12, ymm12, 78H vpunpckhdq ymm5, ymm5, ymm7 vpunpckldq ymm6, ymm6, ymm5 vpshufd ymm7, ymm6, 1EH vmovdqa ymmword ptr [rsp+40H], ymm13 vmovdqa ymmword ptr [rsp+80H], ymm12 vmovdqa ymm12, ymmword ptr [rsp+60H] vmovdqa ymm13, ymmword ptr [rsp+0A0H] vshufps ymm5, ymm12, ymm13, 214 vpshufd ymm6, ymm12, 0FH vpshufd ymm12, ymm5, 39H vshufps ymm5, ymm14, ymm15, 250 vpblendd ymm6, ymm6, ymm5, 0AAH vpunpcklqdq ymm5, ymm15, ymm13 vpblendd ymm5, ymm5, ymm14, 88H vpshufd ymm5, ymm5, 78H vpunpckhdq ymm13, ymm13, ymm15 vpunpckldq ymm14, ymm14, ymm13 vpshufd ymm15, ymm14, 1EH vmovdqa ymm13, ymm6 vmovdqa ymm14, ymm5 vmovdqa ymm5, ymmword ptr [rsp+40H] vmovdqa ymm6, ymmword ptr [rsp+80H] jmp roundloop4 endroundloop4: vpxor ymm0, ymm0, ymm2 vpxor ymm1, ymm1, ymm3 vpxor ymm8, ymm8, ymm10 vpxor ymm9, ymm9, ymm11 mov eax, r13d cmp rdx, r15 jne innerloop4 vmovdqu xmmword ptr [rbx], xmm0 vmovdqu xmmword ptr [rbx+10H], xmm1 vextracti128 xmmword ptr [rbx+20H], ymm0, 01H vextracti128 xmmword ptr [rbx+30H], ymm1, 01H vmovdqu xmmword ptr [rbx+40H], xmm8 vmovdqu xmmword ptr [rbx+50H], xmm9 vextracti128 xmmword ptr [rbx+60H], ymm8, 01H vextracti128 xmmword ptr [rbx+70H], ymm9, 01H vmovaps xmm8, xmmword ptr [rsp+260H] vmovaps xmm0, xmmword ptr [rsp+220H] vmovaps xmm1, xmmword ptr [rsp+230H] vmovaps xmm2, xmmword ptr [rsp+240H] vmovaps xmm3, xmmword ptr [rsp+250H] vblendvps xmm0, xmm0, xmm1, xmm8 vblendvps xmm2, xmm2, xmm3, xmm8 vmovaps xmmword ptr [rsp+220H], xmm0 vmovaps xmmword ptr [rsp+240H], xmm2 add rbx, 128 add rdi, 32 sub rsi, 4 final3blocks: test rsi, 2H je final1blocks vbroadcasti128 ymm0, xmmword ptr [rcx] vbroadcasti128 ymm1, xmmword ptr [rcx+10H] vmovd xmm13, dword ptr [rsp+220H] vpinsrd xmm13, xmm13, dword ptr [rsp+240H], 1 vpinsrd xmm13, xmm13, dword ptr [BLAKE3_BLOCK_LEN], 2 vmovd xmm14, dword ptr [rsp+224H] vpinsrd xmm14, xmm14, dword ptr [rsp+244H], 1 vpinsrd xmm14, xmm14, dword ptr [BLAKE3_BLOCK_LEN], 2 vinserti128 ymm13, ymm13, xmm14, 01H vbroadcasti128 ymm14, xmmword ptr [ROT16] vbroadcasti128 ymm15, xmmword ptr [ROT8] mov r8, qword ptr [rdi] mov r9, qword ptr [rdi+8H] movzx eax, byte ptr [rbp+80H] or eax, r13d xor edx, edx ALIGN 16 innerloop2: mov r14d, eax or eax, r12d add rdx, 64 cmp rdx, r15 cmovne eax, r14d mov dword ptr [rsp+200H], eax vbroadcasti128 ymm2, xmmword ptr [BLAKE3_IV] vpbroadcastd ymm8, dword ptr [rsp+200H] vpblendd ymm3, ymm13, ymm8, 88H vmovups ymm8, ymmword ptr [r8+rdx-40H] vinsertf128 ymm8, ymm8, xmmword ptr [r9+rdx-40H], 01H vmovups ymm9, ymmword ptr [r8+rdx-30H] vinsertf128 ymm9, ymm9, xmmword ptr [r9+rdx-30H], 01H vshufps ymm4, ymm8, ymm9, 136 vshufps ymm5, ymm8, ymm9, 221 vmovups ymm8, ymmword ptr [r8+rdx-20H] vinsertf128 ymm8, ymm8, xmmword ptr [r9+rdx-20H], 01H vmovups ymm9, ymmword ptr [r8+rdx-10H] vinsertf128 ymm9, ymm9, xmmword ptr [r9+rdx-10H], 01H vshufps ymm6, ymm8, ymm9, 136 vshufps ymm7, ymm8, ymm9, 221 vpshufd ymm6, ymm6, 93H vpshufd ymm7, ymm7, 93H mov al, 7 roundloop2: vpaddd ymm0, ymm0, ymm4 vpaddd ymm0, ymm0, ymm1 vpxor ymm3, ymm3, ymm0 vpshufb ymm3, ymm3, ymm14 vpaddd ymm2, ymm2, ymm3 vpxor ymm1, ymm1, ymm2 vpsrld ymm8, ymm1, 12 vpslld ymm1, ymm1, 20 vpor ymm1, ymm1, ymm8 vpaddd ymm0, ymm0, ymm5 vpaddd ymm0, ymm0, ymm1 vpxor ymm3, ymm3, ymm0 vpshufb ymm3, ymm3, ymm15 vpaddd ymm2, ymm2, ymm3 vpxor ymm1, ymm1, ymm2 vpsrld ymm8, ymm1, 7 vpslld ymm1, ymm1, 25 vpor ymm1, ymm1, ymm8 vpshufd ymm0, ymm0, 93H vpshufd ymm3, ymm3, 4EH vpshufd ymm2, ymm2, 39H vpaddd ymm0, ymm0, ymm6 vpaddd ymm0, ymm0, ymm1 vpxor ymm3, ymm3, ymm0 vpshufb ymm3, ymm3, ymm14 vpaddd ymm2, ymm2, ymm3 vpxor ymm1, ymm1, ymm2 vpsrld ymm8, ymm1, 12 vpslld ymm1, ymm1, 20 vpor ymm1, ymm1, ymm8 vpaddd ymm0, ymm0, ymm7 vpaddd ymm0, ymm0, ymm1 vpxor ymm3, ymm3, ymm0 vpshufb ymm3, ymm3, ymm15 vpaddd ymm2, ymm2, ymm3 vpxor ymm1, ymm1, ymm2 vpsrld ymm8, ymm1, 7 vpslld ymm1, ymm1, 25 vpor ymm1, ymm1, ymm8 vpshufd ymm0, ymm0, 39H vpshufd ymm3, ymm3, 4EH vpshufd ymm2, ymm2, 93H dec al jz endroundloop2 vshufps ymm8, ymm4, ymm5, 214 vpshufd ymm9, ymm4, 0FH vpshufd ymm4, ymm8, 39H vshufps ymm8, ymm6, ymm7, 250 vpblendd ymm9, ymm9, ymm8, 0AAH vpunpcklqdq ymm8, ymm7, ymm5 vpblendd ymm8, ymm8, ymm6, 88H vpshufd ymm8, ymm8, 78H vpunpckhdq ymm5, ymm5, ymm7 vpunpckldq ymm6, ymm6, ymm5 vpshufd ymm7, ymm6, 1EH vmovdqa ymm5, ymm9 vmovdqa ymm6, ymm8 jmp roundloop2 endroundloop2: vpxor ymm0, ymm0, ymm2 vpxor ymm1, ymm1, ymm3 mov eax, r13d cmp rdx, r15 jne innerloop2 vmovdqu xmmword ptr [rbx], xmm0 vmovdqu xmmword ptr [rbx+10H], xmm1 vextracti128 xmmword ptr [rbx+20H], ymm0, 01H vextracti128 xmmword ptr [rbx+30H], ymm1, 01H vmovaps ymm8, ymmword ptr [rsp+260H] vmovaps ymm0, ymmword ptr [rsp+220H] vmovups ymm1, ymmword ptr [rsp+228H] vmovaps ymm2, ymmword ptr [rsp+240H] vmovups ymm3, ymmword ptr [rsp+248H] vblendvps ymm0, ymm0, ymm1, ymm8 vblendvps ymm2, ymm2, ymm3, ymm8 vmovaps ymmword ptr [rsp+220H], ymm0 vmovaps ymmword ptr [rsp+240H], ymm2 add rbx, 64 add rdi, 16 sub rsi, 2 final1blocks: test rsi, 1H je unwind vmovdqu xmm0, xmmword ptr [rcx] vmovdqu xmm1, xmmword ptr [rcx+10H] vmovd xmm3, dword ptr [rsp+220H] vpinsrd xmm3, xmm3, dword ptr [rsp+240H], 1 vpinsrd xmm13, xmm3, dword ptr [BLAKE3_BLOCK_LEN], 2 vmovdqa xmm14, xmmword ptr [ROT16] vmovdqa xmm15, xmmword ptr [ROT8] mov r8, qword ptr [rdi] movzx eax, byte ptr [rbp+80H] or eax, r13d xor edx, edx ALIGN 16 innerloop1: mov r14d, eax or eax, r12d add rdx, 64 cmp rdx, r15 cmovne eax, r14d vmovdqa xmm2, xmmword ptr [BLAKE3_IV] vmovdqa xmm3, xmm13 vpinsrd xmm3, xmm3, eax, 3 vmovups xmm8, xmmword ptr [r8+rdx-40H] vmovups xmm9, xmmword ptr [r8+rdx-30H] vshufps xmm4, xmm8, xmm9, 136 vshufps xmm5, xmm8, xmm9, 221 vmovups xmm8, xmmword ptr [r8+rdx-20H] vmovups xmm9, xmmword ptr [r8+rdx-10H] vshufps xmm6, xmm8, xmm9, 136 vshufps xmm7, xmm8, xmm9, 221 vpshufd xmm6, xmm6, 93H vpshufd xmm7, xmm7, 93H mov al, 7 roundloop1: vpaddd xmm0, xmm0, xmm4 vpaddd xmm0, xmm0, xmm1 vpxor xmm3, xmm3, xmm0 vpshufb xmm3, xmm3, xmm14 vpaddd xmm2, xmm2, xmm3 vpxor xmm1, xmm1, xmm2 vpsrld xmm8, xmm1, 12 vpslld xmm1, xmm1, 20 vpor xmm1, xmm1, xmm8 vpaddd xmm0, xmm0, xmm5 vpaddd xmm0, xmm0, xmm1 vpxor xmm3, xmm3, xmm0 vpshufb xmm3, xmm3, xmm15 vpaddd xmm2, xmm2, xmm3 vpxor xmm1, xmm1, xmm2 vpsrld xmm8, xmm1, 7 vpslld xmm1, xmm1, 25 vpor xmm1, xmm1, xmm8 vpshufd xmm0, xmm0, 93H vpshufd xmm3, xmm3, 4EH vpshufd xmm2, xmm2, 39H vpaddd xmm0, xmm0, xmm6 vpaddd xmm0, xmm0, xmm1 vpxor xmm3, xmm3, xmm0 vpshufb xmm3, xmm3, xmm14 vpaddd xmm2, xmm2, xmm3 vpxor xmm1, xmm1, xmm2 vpsrld xmm8, xmm1, 12 vpslld xmm1, xmm1, 20 vpor xmm1, xmm1, xmm8 vpaddd xmm0, xmm0, xmm7 vpaddd xmm0, xmm0, xmm1 vpxor xmm3, xmm3, xmm0 vpshufb xmm3, xmm3, xmm15 vpaddd xmm2, xmm2, xmm3 vpxor xmm1, xmm1, xmm2 vpsrld xmm8, xmm1, 7 vpslld xmm1, xmm1, 25 vpor xmm1, xmm1, xmm8 vpshufd xmm0, xmm0, 39H vpshufd xmm3, xmm3, 4EH vpshufd xmm2, xmm2, 93H dec al jz endroundloop1 vshufps xmm8, xmm4, xmm5, 214 vpshufd xmm9, xmm4, 0FH vpshufd xmm4, xmm8, 39H vshufps xmm8, xmm6, xmm7, 250 vpblendd xmm9, xmm9, xmm8, 0AAH vpunpcklqdq xmm8, xmm7, xmm5 vpblendd xmm8, xmm8, xmm6, 88H vpshufd xmm8, xmm8, 78H vpunpckhdq xmm5, xmm5, xmm7 vpunpckldq xmm6, xmm6, xmm5 vpshufd xmm7, xmm6, 1EH vmovdqa xmm5, xmm9 vmovdqa xmm6, xmm8 jmp roundloop1 endroundloop1: vpxor xmm0, xmm0, xmm2 vpxor xmm1, xmm1, xmm3 mov eax, r13d cmp rdx, r15 jne innerloop1 vmovdqu xmmword ptr [rbx], xmm0 vmovdqu xmmword ptr [rbx+10H], xmm1 jmp unwind _blake3_hash_many_avx2 ENDP blake3_hash_many_avx2 ENDP _TEXT ENDS _RDATA SEGMENT READONLY PAGE ALIAS(".rdata") 'CONST' ALIGN 64 ADD0: dd 0, 1, 2, 3, 4, 5, 6, 7 ADD1: dd 8 dup (8) BLAKE3_IV_0: dd 8 dup (6A09E667H) BLAKE3_IV_1: dd 8 dup (0BB67AE85H) BLAKE3_IV_2: dd 8 dup (3C6EF372H) BLAKE3_IV_3: dd 8 dup (0A54FF53AH) BLAKE3_BLOCK_LEN: dd 8 dup (64) ROT16: db 2, 3, 0, 1, 6, 7, 4, 5, 10, 11, 8, 9, 14, 15, 12, 13 ROT8: db 1, 2, 3, 0, 5, 6, 7, 4, 9, 10, 11, 8, 13, 14, 15, 12 CMP_MSB_MASK: dd 8 dup(80000000H) BLAKE3_IV: dd 6A09E667H, 0BB67AE85H, 3C6EF372H, 0A54FF53AH _RDATA ENDS END librecast/libs/blake3/c/blake3_avx512.c000066400000000000000000001525001502456746400177750ustar00rootroot00000000000000#include "blake3_impl.h" #include #define _mm_shuffle_ps2(a, b, c) \ (_mm_castps_si128( \ _mm_shuffle_ps(_mm_castsi128_ps(a), _mm_castsi128_ps(b), (c)))) INLINE __m128i loadu_128(const uint8_t src[16]) { return _mm_loadu_si128((void*)src); } INLINE __m256i loadu_256(const uint8_t src[32]) { return _mm256_loadu_si256((void*)src); } INLINE __m512i loadu_512(const uint8_t src[64]) { return _mm512_loadu_si512((void*)src); } INLINE void storeu_128(__m128i src, uint8_t dest[16]) { _mm_storeu_si128((void*)dest, src); } INLINE void storeu_256(__m256i src, uint8_t dest[16]) { _mm256_storeu_si256((void*)dest, src); } INLINE void storeu_512(__m512i src, uint8_t dest[16]) { _mm512_storeu_si512((void*)dest, src); } INLINE __m128i add_128(__m128i a, __m128i b) { return _mm_add_epi32(a, b); } INLINE __m256i add_256(__m256i a, __m256i b) { return _mm256_add_epi32(a, b); } INLINE __m512i add_512(__m512i a, __m512i b) { return _mm512_add_epi32(a, b); } INLINE __m128i xor_128(__m128i a, __m128i b) { return _mm_xor_si128(a, b); } INLINE __m256i xor_256(__m256i a, __m256i b) { return _mm256_xor_si256(a, b); } INLINE __m512i xor_512(__m512i a, __m512i b) { return _mm512_xor_si512(a, b); } INLINE __m128i set1_128(uint32_t x) { return _mm_set1_epi32((int32_t)x); } INLINE __m256i set1_256(uint32_t x) { return _mm256_set1_epi32((int32_t)x); } INLINE __m512i set1_512(uint32_t x) { return _mm512_set1_epi32((int32_t)x); } INLINE __m128i set4(uint32_t a, uint32_t b, uint32_t c, uint32_t d) { return _mm_setr_epi32((int32_t)a, (int32_t)b, (int32_t)c, (int32_t)d); } INLINE __m128i rot16_128(__m128i x) { return _mm_ror_epi32(x, 16); } INLINE __m256i rot16_256(__m256i x) { return _mm256_ror_epi32(x, 16); } INLINE __m512i rot16_512(__m512i x) { return _mm512_ror_epi32(x, 16); } INLINE __m128i rot12_128(__m128i x) { return _mm_ror_epi32(x, 12); } INLINE __m256i rot12_256(__m256i x) { return _mm256_ror_epi32(x, 12); } INLINE __m512i rot12_512(__m512i x) { return _mm512_ror_epi32(x, 12); } INLINE __m128i rot8_128(__m128i x) { return _mm_ror_epi32(x, 8); } INLINE __m256i rot8_256(__m256i x) { return _mm256_ror_epi32(x, 8); } INLINE __m512i rot8_512(__m512i x) { return _mm512_ror_epi32(x, 8); } INLINE __m128i rot7_128(__m128i x) { return _mm_ror_epi32(x, 7); } INLINE __m256i rot7_256(__m256i x) { return _mm256_ror_epi32(x, 7); } INLINE __m512i rot7_512(__m512i x) { return _mm512_ror_epi32(x, 7); } /* * ---------------------------------------------------------------------------- * compress_avx512 * ---------------------------------------------------------------------------- */ INLINE void g1(__m128i *row0, __m128i *row1, __m128i *row2, __m128i *row3, __m128i m) { *row0 = add_128(add_128(*row0, m), *row1); *row3 = xor_128(*row3, *row0); *row3 = rot16_128(*row3); *row2 = add_128(*row2, *row3); *row1 = xor_128(*row1, *row2); *row1 = rot12_128(*row1); } INLINE void g2(__m128i *row0, __m128i *row1, __m128i *row2, __m128i *row3, __m128i m) { *row0 = add_128(add_128(*row0, m), *row1); *row3 = xor_128(*row3, *row0); *row3 = rot8_128(*row3); *row2 = add_128(*row2, *row3); *row1 = xor_128(*row1, *row2); *row1 = rot7_128(*row1); } // Note the optimization here of leaving row1 as the unrotated row, rather than // row0. All the message loads below are adjusted to compensate for this. See // discussion at https://github.com/sneves/blake2-avx2/pull/4 INLINE void diagonalize(__m128i *row0, __m128i *row2, __m128i *row3) { *row0 = _mm_shuffle_epi32(*row0, _MM_SHUFFLE(2, 1, 0, 3)); *row3 = _mm_shuffle_epi32(*row3, _MM_SHUFFLE(1, 0, 3, 2)); *row2 = _mm_shuffle_epi32(*row2, _MM_SHUFFLE(0, 3, 2, 1)); } INLINE void undiagonalize(__m128i *row0, __m128i *row2, __m128i *row3) { *row0 = _mm_shuffle_epi32(*row0, _MM_SHUFFLE(0, 3, 2, 1)); *row3 = _mm_shuffle_epi32(*row3, _MM_SHUFFLE(1, 0, 3, 2)); *row2 = _mm_shuffle_epi32(*row2, _MM_SHUFFLE(2, 1, 0, 3)); } INLINE void compress_pre(__m128i rows[4], const uint32_t cv[8], const uint8_t block[BLAKE3_BLOCK_LEN], uint8_t block_len, uint64_t counter, uint8_t flags) { rows[0] = loadu_128((uint8_t *)&cv[0]); rows[1] = loadu_128((uint8_t *)&cv[4]); rows[2] = set4(IV[0], IV[1], IV[2], IV[3]); rows[3] = set4(counter_low(counter), counter_high(counter), (uint32_t)block_len, (uint32_t)flags); __m128i m0 = loadu_128(&block[sizeof(__m128i) * 0]); __m128i m1 = loadu_128(&block[sizeof(__m128i) * 1]); __m128i m2 = loadu_128(&block[sizeof(__m128i) * 2]); __m128i m3 = loadu_128(&block[sizeof(__m128i) * 3]); __m128i t0, t1, t2, t3, tt; // Round 1. The first round permutes the message words from the original // input order, into the groups that get mixed in parallel. t0 = _mm_shuffle_ps2(m0, m1, _MM_SHUFFLE(2, 0, 2, 0)); // 6 4 2 0 g1(&rows[0], &rows[1], &rows[2], &rows[3], t0); t1 = _mm_shuffle_ps2(m0, m1, _MM_SHUFFLE(3, 1, 3, 1)); // 7 5 3 1 g2(&rows[0], &rows[1], &rows[2], &rows[3], t1); diagonalize(&rows[0], &rows[2], &rows[3]); t2 = _mm_shuffle_ps2(m2, m3, _MM_SHUFFLE(2, 0, 2, 0)); // 14 12 10 8 t2 = _mm_shuffle_epi32(t2, _MM_SHUFFLE(2, 1, 0, 3)); // 12 10 8 14 g1(&rows[0], &rows[1], &rows[2], &rows[3], t2); t3 = _mm_shuffle_ps2(m2, m3, _MM_SHUFFLE(3, 1, 3, 1)); // 15 13 11 9 t3 = _mm_shuffle_epi32(t3, _MM_SHUFFLE(2, 1, 0, 3)); // 13 11 9 15 g2(&rows[0], &rows[1], &rows[2], &rows[3], t3); undiagonalize(&rows[0], &rows[2], &rows[3]); m0 = t0; m1 = t1; m2 = t2; m3 = t3; // Round 2. This round and all following rounds apply a fixed permutation // to the message words from the round before. t0 = _mm_shuffle_ps2(m0, m1, _MM_SHUFFLE(3, 1, 1, 2)); t0 = _mm_shuffle_epi32(t0, _MM_SHUFFLE(0, 3, 2, 1)); g1(&rows[0], &rows[1], &rows[2], &rows[3], t0); t1 = _mm_shuffle_ps2(m2, m3, _MM_SHUFFLE(3, 3, 2, 2)); tt = _mm_shuffle_epi32(m0, _MM_SHUFFLE(0, 0, 3, 3)); t1 = _mm_blend_epi16(tt, t1, 0xCC); g2(&rows[0], &rows[1], &rows[2], &rows[3], t1); diagonalize(&rows[0], &rows[2], &rows[3]); t2 = _mm_unpacklo_epi64(m3, m1); tt = _mm_blend_epi16(t2, m2, 0xC0); t2 = _mm_shuffle_epi32(tt, _MM_SHUFFLE(1, 3, 2, 0)); g1(&rows[0], &rows[1], &rows[2], &rows[3], t2); t3 = _mm_unpackhi_epi32(m1, m3); tt = _mm_unpacklo_epi32(m2, t3); t3 = _mm_shuffle_epi32(tt, _MM_SHUFFLE(0, 1, 3, 2)); g2(&rows[0], &rows[1], &rows[2], &rows[3], t3); undiagonalize(&rows[0], &rows[2], &rows[3]); m0 = t0; m1 = t1; m2 = t2; m3 = t3; // Round 3 t0 = _mm_shuffle_ps2(m0, m1, _MM_SHUFFLE(3, 1, 1, 2)); t0 = _mm_shuffle_epi32(t0, _MM_SHUFFLE(0, 3, 2, 1)); g1(&rows[0], &rows[1], &rows[2], &rows[3], t0); t1 = _mm_shuffle_ps2(m2, m3, _MM_SHUFFLE(3, 3, 2, 2)); tt = _mm_shuffle_epi32(m0, _MM_SHUFFLE(0, 0, 3, 3)); t1 = _mm_blend_epi16(tt, t1, 0xCC); g2(&rows[0], &rows[1], &rows[2], &rows[3], t1); diagonalize(&rows[0], &rows[2], &rows[3]); t2 = _mm_unpacklo_epi64(m3, m1); tt = _mm_blend_epi16(t2, m2, 0xC0); t2 = _mm_shuffle_epi32(tt, _MM_SHUFFLE(1, 3, 2, 0)); g1(&rows[0], &rows[1], &rows[2], &rows[3], t2); t3 = _mm_unpackhi_epi32(m1, m3); tt = _mm_unpacklo_epi32(m2, t3); t3 = _mm_shuffle_epi32(tt, _MM_SHUFFLE(0, 1, 3, 2)); g2(&rows[0], &rows[1], &rows[2], &rows[3], t3); undiagonalize(&rows[0], &rows[2], &rows[3]); m0 = t0; m1 = t1; m2 = t2; m3 = t3; // Round 4 t0 = _mm_shuffle_ps2(m0, m1, _MM_SHUFFLE(3, 1, 1, 2)); t0 = _mm_shuffle_epi32(t0, _MM_SHUFFLE(0, 3, 2, 1)); g1(&rows[0], &rows[1], &rows[2], &rows[3], t0); t1 = _mm_shuffle_ps2(m2, m3, _MM_SHUFFLE(3, 3, 2, 2)); tt = _mm_shuffle_epi32(m0, _MM_SHUFFLE(0, 0, 3, 3)); t1 = _mm_blend_epi16(tt, t1, 0xCC); g2(&rows[0], &rows[1], &rows[2], &rows[3], t1); diagonalize(&rows[0], &rows[2], &rows[3]); t2 = _mm_unpacklo_epi64(m3, m1); tt = _mm_blend_epi16(t2, m2, 0xC0); t2 = _mm_shuffle_epi32(tt, _MM_SHUFFLE(1, 3, 2, 0)); g1(&rows[0], &rows[1], &rows[2], &rows[3], t2); t3 = _mm_unpackhi_epi32(m1, m3); tt = _mm_unpacklo_epi32(m2, t3); t3 = _mm_shuffle_epi32(tt, _MM_SHUFFLE(0, 1, 3, 2)); g2(&rows[0], &rows[1], &rows[2], &rows[3], t3); undiagonalize(&rows[0], &rows[2], &rows[3]); m0 = t0; m1 = t1; m2 = t2; m3 = t3; // Round 5 t0 = _mm_shuffle_ps2(m0, m1, _MM_SHUFFLE(3, 1, 1, 2)); t0 = _mm_shuffle_epi32(t0, _MM_SHUFFLE(0, 3, 2, 1)); g1(&rows[0], &rows[1], &rows[2], &rows[3], t0); t1 = _mm_shuffle_ps2(m2, m3, _MM_SHUFFLE(3, 3, 2, 2)); tt = _mm_shuffle_epi32(m0, _MM_SHUFFLE(0, 0, 3, 3)); t1 = _mm_blend_epi16(tt, t1, 0xCC); g2(&rows[0], &rows[1], &rows[2], &rows[3], t1); diagonalize(&rows[0], &rows[2], &rows[3]); t2 = _mm_unpacklo_epi64(m3, m1); tt = _mm_blend_epi16(t2, m2, 0xC0); t2 = _mm_shuffle_epi32(tt, _MM_SHUFFLE(1, 3, 2, 0)); g1(&rows[0], &rows[1], &rows[2], &rows[3], t2); t3 = _mm_unpackhi_epi32(m1, m3); tt = _mm_unpacklo_epi32(m2, t3); t3 = _mm_shuffle_epi32(tt, _MM_SHUFFLE(0, 1, 3, 2)); g2(&rows[0], &rows[1], &rows[2], &rows[3], t3); undiagonalize(&rows[0], &rows[2], &rows[3]); m0 = t0; m1 = t1; m2 = t2; m3 = t3; // Round 6 t0 = _mm_shuffle_ps2(m0, m1, _MM_SHUFFLE(3, 1, 1, 2)); t0 = _mm_shuffle_epi32(t0, _MM_SHUFFLE(0, 3, 2, 1)); g1(&rows[0], &rows[1], &rows[2], &rows[3], t0); t1 = _mm_shuffle_ps2(m2, m3, _MM_SHUFFLE(3, 3, 2, 2)); tt = _mm_shuffle_epi32(m0, _MM_SHUFFLE(0, 0, 3, 3)); t1 = _mm_blend_epi16(tt, t1, 0xCC); g2(&rows[0], &rows[1], &rows[2], &rows[3], t1); diagonalize(&rows[0], &rows[2], &rows[3]); t2 = _mm_unpacklo_epi64(m3, m1); tt = _mm_blend_epi16(t2, m2, 0xC0); t2 = _mm_shuffle_epi32(tt, _MM_SHUFFLE(1, 3, 2, 0)); g1(&rows[0], &rows[1], &rows[2], &rows[3], t2); t3 = _mm_unpackhi_epi32(m1, m3); tt = _mm_unpacklo_epi32(m2, t3); t3 = _mm_shuffle_epi32(tt, _MM_SHUFFLE(0, 1, 3, 2)); g2(&rows[0], &rows[1], &rows[2], &rows[3], t3); undiagonalize(&rows[0], &rows[2], &rows[3]); m0 = t0; m1 = t1; m2 = t2; m3 = t3; // Round 7 t0 = _mm_shuffle_ps2(m0, m1, _MM_SHUFFLE(3, 1, 1, 2)); t0 = _mm_shuffle_epi32(t0, _MM_SHUFFLE(0, 3, 2, 1)); g1(&rows[0], &rows[1], &rows[2], &rows[3], t0); t1 = _mm_shuffle_ps2(m2, m3, _MM_SHUFFLE(3, 3, 2, 2)); tt = _mm_shuffle_epi32(m0, _MM_SHUFFLE(0, 0, 3, 3)); t1 = _mm_blend_epi16(tt, t1, 0xCC); g2(&rows[0], &rows[1], &rows[2], &rows[3], t1); diagonalize(&rows[0], &rows[2], &rows[3]); t2 = _mm_unpacklo_epi64(m3, m1); tt = _mm_blend_epi16(t2, m2, 0xC0); t2 = _mm_shuffle_epi32(tt, _MM_SHUFFLE(1, 3, 2, 0)); g1(&rows[0], &rows[1], &rows[2], &rows[3], t2); t3 = _mm_unpackhi_epi32(m1, m3); tt = _mm_unpacklo_epi32(m2, t3); t3 = _mm_shuffle_epi32(tt, _MM_SHUFFLE(0, 1, 3, 2)); g2(&rows[0], &rows[1], &rows[2], &rows[3], t3); undiagonalize(&rows[0], &rows[2], &rows[3]); } void blake3_compress_xof_avx512(const uint32_t cv[8], const uint8_t block[BLAKE3_BLOCK_LEN], uint8_t block_len, uint64_t counter, uint8_t flags, uint8_t out[64]) { __m128i rows[4]; compress_pre(rows, cv, block, block_len, counter, flags); storeu_128(xor_128(rows[0], rows[2]), &out[0]); storeu_128(xor_128(rows[1], rows[3]), &out[16]); storeu_128(xor_128(rows[2], loadu_128((uint8_t *)&cv[0])), &out[32]); storeu_128(xor_128(rows[3], loadu_128((uint8_t *)&cv[4])), &out[48]); } void blake3_compress_in_place_avx512(uint32_t cv[8], const uint8_t block[BLAKE3_BLOCK_LEN], uint8_t block_len, uint64_t counter, uint8_t flags) { __m128i rows[4]; compress_pre(rows, cv, block, block_len, counter, flags); storeu_128(xor_128(rows[0], rows[2]), (uint8_t *)&cv[0]); storeu_128(xor_128(rows[1], rows[3]), (uint8_t *)&cv[4]); } /* * ---------------------------------------------------------------------------- * hash4_avx512 * ---------------------------------------------------------------------------- */ INLINE void round_fn4(__m128i v[16], __m128i m[16], size_t r) { v[0] = add_128(v[0], m[(size_t)MSG_SCHEDULE[r][0]]); v[1] = add_128(v[1], m[(size_t)MSG_SCHEDULE[r][2]]); v[2] = add_128(v[2], m[(size_t)MSG_SCHEDULE[r][4]]); v[3] = add_128(v[3], m[(size_t)MSG_SCHEDULE[r][6]]); v[0] = add_128(v[0], v[4]); v[1] = add_128(v[1], v[5]); v[2] = add_128(v[2], v[6]); v[3] = add_128(v[3], v[7]); v[12] = xor_128(v[12], v[0]); v[13] = xor_128(v[13], v[1]); v[14] = xor_128(v[14], v[2]); v[15] = xor_128(v[15], v[3]); v[12] = rot16_128(v[12]); v[13] = rot16_128(v[13]); v[14] = rot16_128(v[14]); v[15] = rot16_128(v[15]); v[8] = add_128(v[8], v[12]); v[9] = add_128(v[9], v[13]); v[10] = add_128(v[10], v[14]); v[11] = add_128(v[11], v[15]); v[4] = xor_128(v[4], v[8]); v[5] = xor_128(v[5], v[9]); v[6] = xor_128(v[6], v[10]); v[7] = xor_128(v[7], v[11]); v[4] = rot12_128(v[4]); v[5] = rot12_128(v[5]); v[6] = rot12_128(v[6]); v[7] = rot12_128(v[7]); v[0] = add_128(v[0], m[(size_t)MSG_SCHEDULE[r][1]]); v[1] = add_128(v[1], m[(size_t)MSG_SCHEDULE[r][3]]); v[2] = add_128(v[2], m[(size_t)MSG_SCHEDULE[r][5]]); v[3] = add_128(v[3], m[(size_t)MSG_SCHEDULE[r][7]]); v[0] = add_128(v[0], v[4]); v[1] = add_128(v[1], v[5]); v[2] = add_128(v[2], v[6]); v[3] = add_128(v[3], v[7]); v[12] = xor_128(v[12], v[0]); v[13] = xor_128(v[13], v[1]); v[14] = xor_128(v[14], v[2]); v[15] = xor_128(v[15], v[3]); v[12] = rot8_128(v[12]); v[13] = rot8_128(v[13]); v[14] = rot8_128(v[14]); v[15] = rot8_128(v[15]); v[8] = add_128(v[8], v[12]); v[9] = add_128(v[9], v[13]); v[10] = add_128(v[10], v[14]); v[11] = add_128(v[11], v[15]); v[4] = xor_128(v[4], v[8]); v[5] = xor_128(v[5], v[9]); v[6] = xor_128(v[6], v[10]); v[7] = xor_128(v[7], v[11]); v[4] = rot7_128(v[4]); v[5] = rot7_128(v[5]); v[6] = rot7_128(v[6]); v[7] = rot7_128(v[7]); v[0] = add_128(v[0], m[(size_t)MSG_SCHEDULE[r][8]]); v[1] = add_128(v[1], m[(size_t)MSG_SCHEDULE[r][10]]); v[2] = add_128(v[2], m[(size_t)MSG_SCHEDULE[r][12]]); v[3] = add_128(v[3], m[(size_t)MSG_SCHEDULE[r][14]]); v[0] = add_128(v[0], v[5]); v[1] = add_128(v[1], v[6]); v[2] = add_128(v[2], v[7]); v[3] = add_128(v[3], v[4]); v[15] = xor_128(v[15], v[0]); v[12] = xor_128(v[12], v[1]); v[13] = xor_128(v[13], v[2]); v[14] = xor_128(v[14], v[3]); v[15] = rot16_128(v[15]); v[12] = rot16_128(v[12]); v[13] = rot16_128(v[13]); v[14] = rot16_128(v[14]); v[10] = add_128(v[10], v[15]); v[11] = add_128(v[11], v[12]); v[8] = add_128(v[8], v[13]); v[9] = add_128(v[9], v[14]); v[5] = xor_128(v[5], v[10]); v[6] = xor_128(v[6], v[11]); v[7] = xor_128(v[7], v[8]); v[4] = xor_128(v[4], v[9]); v[5] = rot12_128(v[5]); v[6] = rot12_128(v[6]); v[7] = rot12_128(v[7]); v[4] = rot12_128(v[4]); v[0] = add_128(v[0], m[(size_t)MSG_SCHEDULE[r][9]]); v[1] = add_128(v[1], m[(size_t)MSG_SCHEDULE[r][11]]); v[2] = add_128(v[2], m[(size_t)MSG_SCHEDULE[r][13]]); v[3] = add_128(v[3], m[(size_t)MSG_SCHEDULE[r][15]]); v[0] = add_128(v[0], v[5]); v[1] = add_128(v[1], v[6]); v[2] = add_128(v[2], v[7]); v[3] = add_128(v[3], v[4]); v[15] = xor_128(v[15], v[0]); v[12] = xor_128(v[12], v[1]); v[13] = xor_128(v[13], v[2]); v[14] = xor_128(v[14], v[3]); v[15] = rot8_128(v[15]); v[12] = rot8_128(v[12]); v[13] = rot8_128(v[13]); v[14] = rot8_128(v[14]); v[10] = add_128(v[10], v[15]); v[11] = add_128(v[11], v[12]); v[8] = add_128(v[8], v[13]); v[9] = add_128(v[9], v[14]); v[5] = xor_128(v[5], v[10]); v[6] = xor_128(v[6], v[11]); v[7] = xor_128(v[7], v[8]); v[4] = xor_128(v[4], v[9]); v[5] = rot7_128(v[5]); v[6] = rot7_128(v[6]); v[7] = rot7_128(v[7]); v[4] = rot7_128(v[4]); } INLINE void transpose_vecs_128(__m128i vecs[4]) { // Interleave 32-bit lanes. The low unpack is lanes 00/11 and the high is // 22/33. Note that this doesn't split the vector into two lanes, as the // AVX2 counterparts do. __m128i ab_01 = _mm_unpacklo_epi32(vecs[0], vecs[1]); __m128i ab_23 = _mm_unpackhi_epi32(vecs[0], vecs[1]); __m128i cd_01 = _mm_unpacklo_epi32(vecs[2], vecs[3]); __m128i cd_23 = _mm_unpackhi_epi32(vecs[2], vecs[3]); // Interleave 64-bit lanes. __m128i abcd_0 = _mm_unpacklo_epi64(ab_01, cd_01); __m128i abcd_1 = _mm_unpackhi_epi64(ab_01, cd_01); __m128i abcd_2 = _mm_unpacklo_epi64(ab_23, cd_23); __m128i abcd_3 = _mm_unpackhi_epi64(ab_23, cd_23); vecs[0] = abcd_0; vecs[1] = abcd_1; vecs[2] = abcd_2; vecs[3] = abcd_3; } INLINE void transpose_msg_vecs4(const uint8_t *const *inputs, size_t block_offset, __m128i out[16]) { out[0] = loadu_128(&inputs[0][block_offset + 0 * sizeof(__m128i)]); out[1] = loadu_128(&inputs[1][block_offset + 0 * sizeof(__m128i)]); out[2] = loadu_128(&inputs[2][block_offset + 0 * sizeof(__m128i)]); out[3] = loadu_128(&inputs[3][block_offset + 0 * sizeof(__m128i)]); out[4] = loadu_128(&inputs[0][block_offset + 1 * sizeof(__m128i)]); out[5] = loadu_128(&inputs[1][block_offset + 1 * sizeof(__m128i)]); out[6] = loadu_128(&inputs[2][block_offset + 1 * sizeof(__m128i)]); out[7] = loadu_128(&inputs[3][block_offset + 1 * sizeof(__m128i)]); out[8] = loadu_128(&inputs[0][block_offset + 2 * sizeof(__m128i)]); out[9] = loadu_128(&inputs[1][block_offset + 2 * sizeof(__m128i)]); out[10] = loadu_128(&inputs[2][block_offset + 2 * sizeof(__m128i)]); out[11] = loadu_128(&inputs[3][block_offset + 2 * sizeof(__m128i)]); out[12] = loadu_128(&inputs[0][block_offset + 3 * sizeof(__m128i)]); out[13] = loadu_128(&inputs[1][block_offset + 3 * sizeof(__m128i)]); out[14] = loadu_128(&inputs[2][block_offset + 3 * sizeof(__m128i)]); out[15] = loadu_128(&inputs[3][block_offset + 3 * sizeof(__m128i)]); for (size_t i = 0; i < 4; ++i) { _mm_prefetch((const void *)&inputs[i][block_offset + 256], _MM_HINT_T0); } transpose_vecs_128(&out[0]); transpose_vecs_128(&out[4]); transpose_vecs_128(&out[8]); transpose_vecs_128(&out[12]); } INLINE void load_counters4(uint64_t counter, bool increment_counter, __m128i *out_lo, __m128i *out_hi) { uint64_t mask = (increment_counter ? ~0 : 0); __m256i mask_vec = _mm256_set1_epi64x(mask); __m256i deltas = _mm256_setr_epi64x(0, 1, 2, 3); deltas = _mm256_and_si256(mask_vec, deltas); __m256i counters = _mm256_add_epi64(_mm256_set1_epi64x((int64_t)counter), deltas); *out_lo = _mm256_cvtepi64_epi32(counters); *out_hi = _mm256_cvtepi64_epi32(_mm256_srli_epi64(counters, 32)); } static void blake3_hash4_avx512(const uint8_t *const *inputs, size_t blocks, const uint32_t key[8], uint64_t counter, bool increment_counter, uint8_t flags, uint8_t flags_start, uint8_t flags_end, uint8_t *out) { __m128i h_vecs[8] = { set1_128(key[0]), set1_128(key[1]), set1_128(key[2]), set1_128(key[3]), set1_128(key[4]), set1_128(key[5]), set1_128(key[6]), set1_128(key[7]), }; __m128i counter_low_vec, counter_high_vec; load_counters4(counter, increment_counter, &counter_low_vec, &counter_high_vec); uint8_t block_flags = flags | flags_start; for (size_t block = 0; block < blocks; block++) { if (block + 1 == blocks) { block_flags |= flags_end; } __m128i block_len_vec = set1_128(BLAKE3_BLOCK_LEN); __m128i block_flags_vec = set1_128(block_flags); __m128i msg_vecs[16]; transpose_msg_vecs4(inputs, block * BLAKE3_BLOCK_LEN, msg_vecs); __m128i v[16] = { h_vecs[0], h_vecs[1], h_vecs[2], h_vecs[3], h_vecs[4], h_vecs[5], h_vecs[6], h_vecs[7], set1_128(IV[0]), set1_128(IV[1]), set1_128(IV[2]), set1_128(IV[3]), counter_low_vec, counter_high_vec, block_len_vec, block_flags_vec, }; round_fn4(v, msg_vecs, 0); round_fn4(v, msg_vecs, 1); round_fn4(v, msg_vecs, 2); round_fn4(v, msg_vecs, 3); round_fn4(v, msg_vecs, 4); round_fn4(v, msg_vecs, 5); round_fn4(v, msg_vecs, 6); h_vecs[0] = xor_128(v[0], v[8]); h_vecs[1] = xor_128(v[1], v[9]); h_vecs[2] = xor_128(v[2], v[10]); h_vecs[3] = xor_128(v[3], v[11]); h_vecs[4] = xor_128(v[4], v[12]); h_vecs[5] = xor_128(v[5], v[13]); h_vecs[6] = xor_128(v[6], v[14]); h_vecs[7] = xor_128(v[7], v[15]); block_flags = flags; } transpose_vecs_128(&h_vecs[0]); transpose_vecs_128(&h_vecs[4]); // The first four vecs now contain the first half of each output, and the // second four vecs contain the second half of each output. storeu_128(h_vecs[0], &out[0 * sizeof(__m128i)]); storeu_128(h_vecs[4], &out[1 * sizeof(__m128i)]); storeu_128(h_vecs[1], &out[2 * sizeof(__m128i)]); storeu_128(h_vecs[5], &out[3 * sizeof(__m128i)]); storeu_128(h_vecs[2], &out[4 * sizeof(__m128i)]); storeu_128(h_vecs[6], &out[5 * sizeof(__m128i)]); storeu_128(h_vecs[3], &out[6 * sizeof(__m128i)]); storeu_128(h_vecs[7], &out[7 * sizeof(__m128i)]); } static void blake3_xof4_avx512(const uint32_t cv[8], const uint8_t block[BLAKE3_BLOCK_LEN], uint8_t block_len, uint64_t counter, uint8_t flags, uint8_t out[4 * 64]) { __m128i h_vecs[8] = { set1_128(cv[0]), set1_128(cv[1]), set1_128(cv[2]), set1_128(cv[3]), set1_128(cv[4]), set1_128(cv[5]), set1_128(cv[6]), set1_128(cv[7]), }; uint32_t block_words[16]; load_block_words(block, block_words); __m128i msg_vecs[16]; for (size_t i = 0; i < 16; i++) { msg_vecs[i] = set1_128(block_words[i]); } __m128i counter_low_vec, counter_high_vec; load_counters4(counter, true, &counter_low_vec, &counter_high_vec); __m128i block_len_vec = set1_128(block_len); __m128i block_flags_vec = set1_128(flags); __m128i v[16] = { h_vecs[0], h_vecs[1], h_vecs[2], h_vecs[3], h_vecs[4], h_vecs[5], h_vecs[6], h_vecs[7], set1_128(IV[0]), set1_128(IV[1]), set1_128(IV[2]), set1_128(IV[3]), counter_low_vec, counter_high_vec, block_len_vec, block_flags_vec, }; round_fn4(v, msg_vecs, 0); round_fn4(v, msg_vecs, 1); round_fn4(v, msg_vecs, 2); round_fn4(v, msg_vecs, 3); round_fn4(v, msg_vecs, 4); round_fn4(v, msg_vecs, 5); round_fn4(v, msg_vecs, 6); for (size_t i = 0; i < 8; i++) { v[i] = xor_128(v[i], v[i+8]); v[i+8] = xor_128(v[i+8], h_vecs[i]); } transpose_vecs_128(&v[0]); transpose_vecs_128(&v[4]); transpose_vecs_128(&v[8]); transpose_vecs_128(&v[12]); for (size_t i = 0; i < 4; i++) { storeu_128(v[i+ 0], &out[(4*i+0) * sizeof(__m128i)]); storeu_128(v[i+ 4], &out[(4*i+1) * sizeof(__m128i)]); storeu_128(v[i+ 8], &out[(4*i+2) * sizeof(__m128i)]); storeu_128(v[i+12], &out[(4*i+3) * sizeof(__m128i)]); } } /* * ---------------------------------------------------------------------------- * hash8_avx512 * ---------------------------------------------------------------------------- */ INLINE void round_fn8(__m256i v[16], __m256i m[16], size_t r) { v[0] = add_256(v[0], m[(size_t)MSG_SCHEDULE[r][0]]); v[1] = add_256(v[1], m[(size_t)MSG_SCHEDULE[r][2]]); v[2] = add_256(v[2], m[(size_t)MSG_SCHEDULE[r][4]]); v[3] = add_256(v[3], m[(size_t)MSG_SCHEDULE[r][6]]); v[0] = add_256(v[0], v[4]); v[1] = add_256(v[1], v[5]); v[2] = add_256(v[2], v[6]); v[3] = add_256(v[3], v[7]); v[12] = xor_256(v[12], v[0]); v[13] = xor_256(v[13], v[1]); v[14] = xor_256(v[14], v[2]); v[15] = xor_256(v[15], v[3]); v[12] = rot16_256(v[12]); v[13] = rot16_256(v[13]); v[14] = rot16_256(v[14]); v[15] = rot16_256(v[15]); v[8] = add_256(v[8], v[12]); v[9] = add_256(v[9], v[13]); v[10] = add_256(v[10], v[14]); v[11] = add_256(v[11], v[15]); v[4] = xor_256(v[4], v[8]); v[5] = xor_256(v[5], v[9]); v[6] = xor_256(v[6], v[10]); v[7] = xor_256(v[7], v[11]); v[4] = rot12_256(v[4]); v[5] = rot12_256(v[5]); v[6] = rot12_256(v[6]); v[7] = rot12_256(v[7]); v[0] = add_256(v[0], m[(size_t)MSG_SCHEDULE[r][1]]); v[1] = add_256(v[1], m[(size_t)MSG_SCHEDULE[r][3]]); v[2] = add_256(v[2], m[(size_t)MSG_SCHEDULE[r][5]]); v[3] = add_256(v[3], m[(size_t)MSG_SCHEDULE[r][7]]); v[0] = add_256(v[0], v[4]); v[1] = add_256(v[1], v[5]); v[2] = add_256(v[2], v[6]); v[3] = add_256(v[3], v[7]); v[12] = xor_256(v[12], v[0]); v[13] = xor_256(v[13], v[1]); v[14] = xor_256(v[14], v[2]); v[15] = xor_256(v[15], v[3]); v[12] = rot8_256(v[12]); v[13] = rot8_256(v[13]); v[14] = rot8_256(v[14]); v[15] = rot8_256(v[15]); v[8] = add_256(v[8], v[12]); v[9] = add_256(v[9], v[13]); v[10] = add_256(v[10], v[14]); v[11] = add_256(v[11], v[15]); v[4] = xor_256(v[4], v[8]); v[5] = xor_256(v[5], v[9]); v[6] = xor_256(v[6], v[10]); v[7] = xor_256(v[7], v[11]); v[4] = rot7_256(v[4]); v[5] = rot7_256(v[5]); v[6] = rot7_256(v[6]); v[7] = rot7_256(v[7]); v[0] = add_256(v[0], m[(size_t)MSG_SCHEDULE[r][8]]); v[1] = add_256(v[1], m[(size_t)MSG_SCHEDULE[r][10]]); v[2] = add_256(v[2], m[(size_t)MSG_SCHEDULE[r][12]]); v[3] = add_256(v[3], m[(size_t)MSG_SCHEDULE[r][14]]); v[0] = add_256(v[0], v[5]); v[1] = add_256(v[1], v[6]); v[2] = add_256(v[2], v[7]); v[3] = add_256(v[3], v[4]); v[15] = xor_256(v[15], v[0]); v[12] = xor_256(v[12], v[1]); v[13] = xor_256(v[13], v[2]); v[14] = xor_256(v[14], v[3]); v[15] = rot16_256(v[15]); v[12] = rot16_256(v[12]); v[13] = rot16_256(v[13]); v[14] = rot16_256(v[14]); v[10] = add_256(v[10], v[15]); v[11] = add_256(v[11], v[12]); v[8] = add_256(v[8], v[13]); v[9] = add_256(v[9], v[14]); v[5] = xor_256(v[5], v[10]); v[6] = xor_256(v[6], v[11]); v[7] = xor_256(v[7], v[8]); v[4] = xor_256(v[4], v[9]); v[5] = rot12_256(v[5]); v[6] = rot12_256(v[6]); v[7] = rot12_256(v[7]); v[4] = rot12_256(v[4]); v[0] = add_256(v[0], m[(size_t)MSG_SCHEDULE[r][9]]); v[1] = add_256(v[1], m[(size_t)MSG_SCHEDULE[r][11]]); v[2] = add_256(v[2], m[(size_t)MSG_SCHEDULE[r][13]]); v[3] = add_256(v[3], m[(size_t)MSG_SCHEDULE[r][15]]); v[0] = add_256(v[0], v[5]); v[1] = add_256(v[1], v[6]); v[2] = add_256(v[2], v[7]); v[3] = add_256(v[3], v[4]); v[15] = xor_256(v[15], v[0]); v[12] = xor_256(v[12], v[1]); v[13] = xor_256(v[13], v[2]); v[14] = xor_256(v[14], v[3]); v[15] = rot8_256(v[15]); v[12] = rot8_256(v[12]); v[13] = rot8_256(v[13]); v[14] = rot8_256(v[14]); v[10] = add_256(v[10], v[15]); v[11] = add_256(v[11], v[12]); v[8] = add_256(v[8], v[13]); v[9] = add_256(v[9], v[14]); v[5] = xor_256(v[5], v[10]); v[6] = xor_256(v[6], v[11]); v[7] = xor_256(v[7], v[8]); v[4] = xor_256(v[4], v[9]); v[5] = rot7_256(v[5]); v[6] = rot7_256(v[6]); v[7] = rot7_256(v[7]); v[4] = rot7_256(v[4]); } INLINE void transpose_vecs_256(__m256i vecs[8]) { // Interleave 32-bit lanes. The low unpack is lanes 00/11/44/55, and the high // is 22/33/66/77. __m256i ab_0145 = _mm256_unpacklo_epi32(vecs[0], vecs[1]); __m256i ab_2367 = _mm256_unpackhi_epi32(vecs[0], vecs[1]); __m256i cd_0145 = _mm256_unpacklo_epi32(vecs[2], vecs[3]); __m256i cd_2367 = _mm256_unpackhi_epi32(vecs[2], vecs[3]); __m256i ef_0145 = _mm256_unpacklo_epi32(vecs[4], vecs[5]); __m256i ef_2367 = _mm256_unpackhi_epi32(vecs[4], vecs[5]); __m256i gh_0145 = _mm256_unpacklo_epi32(vecs[6], vecs[7]); __m256i gh_2367 = _mm256_unpackhi_epi32(vecs[6], vecs[7]); // Interleave 64-bit lanes. The low unpack is lanes 00/22 and the high is // 11/33. __m256i abcd_04 = _mm256_unpacklo_epi64(ab_0145, cd_0145); __m256i abcd_15 = _mm256_unpackhi_epi64(ab_0145, cd_0145); __m256i abcd_26 = _mm256_unpacklo_epi64(ab_2367, cd_2367); __m256i abcd_37 = _mm256_unpackhi_epi64(ab_2367, cd_2367); __m256i efgh_04 = _mm256_unpacklo_epi64(ef_0145, gh_0145); __m256i efgh_15 = _mm256_unpackhi_epi64(ef_0145, gh_0145); __m256i efgh_26 = _mm256_unpacklo_epi64(ef_2367, gh_2367); __m256i efgh_37 = _mm256_unpackhi_epi64(ef_2367, gh_2367); // Interleave 128-bit lanes. vecs[0] = _mm256_permute2x128_si256(abcd_04, efgh_04, 0x20); vecs[1] = _mm256_permute2x128_si256(abcd_15, efgh_15, 0x20); vecs[2] = _mm256_permute2x128_si256(abcd_26, efgh_26, 0x20); vecs[3] = _mm256_permute2x128_si256(abcd_37, efgh_37, 0x20); vecs[4] = _mm256_permute2x128_si256(abcd_04, efgh_04, 0x31); vecs[5] = _mm256_permute2x128_si256(abcd_15, efgh_15, 0x31); vecs[6] = _mm256_permute2x128_si256(abcd_26, efgh_26, 0x31); vecs[7] = _mm256_permute2x128_si256(abcd_37, efgh_37, 0x31); } INLINE void transpose_msg_vecs8(const uint8_t *const *inputs, size_t block_offset, __m256i out[16]) { out[0] = loadu_256(&inputs[0][block_offset + 0 * sizeof(__m256i)]); out[1] = loadu_256(&inputs[1][block_offset + 0 * sizeof(__m256i)]); out[2] = loadu_256(&inputs[2][block_offset + 0 * sizeof(__m256i)]); out[3] = loadu_256(&inputs[3][block_offset + 0 * sizeof(__m256i)]); out[4] = loadu_256(&inputs[4][block_offset + 0 * sizeof(__m256i)]); out[5] = loadu_256(&inputs[5][block_offset + 0 * sizeof(__m256i)]); out[6] = loadu_256(&inputs[6][block_offset + 0 * sizeof(__m256i)]); out[7] = loadu_256(&inputs[7][block_offset + 0 * sizeof(__m256i)]); out[8] = loadu_256(&inputs[0][block_offset + 1 * sizeof(__m256i)]); out[9] = loadu_256(&inputs[1][block_offset + 1 * sizeof(__m256i)]); out[10] = loadu_256(&inputs[2][block_offset + 1 * sizeof(__m256i)]); out[11] = loadu_256(&inputs[3][block_offset + 1 * sizeof(__m256i)]); out[12] = loadu_256(&inputs[4][block_offset + 1 * sizeof(__m256i)]); out[13] = loadu_256(&inputs[5][block_offset + 1 * sizeof(__m256i)]); out[14] = loadu_256(&inputs[6][block_offset + 1 * sizeof(__m256i)]); out[15] = loadu_256(&inputs[7][block_offset + 1 * sizeof(__m256i)]); for (size_t i = 0; i < 8; ++i) { _mm_prefetch((const void *)&inputs[i][block_offset + 256], _MM_HINT_T0); } transpose_vecs_256(&out[0]); transpose_vecs_256(&out[8]); } INLINE void load_counters8(uint64_t counter, bool increment_counter, __m256i *out_lo, __m256i *out_hi) { uint64_t mask = (increment_counter ? ~0 : 0); __m512i mask_vec = _mm512_set1_epi64(mask); __m512i deltas = _mm512_setr_epi64(0, 1, 2, 3, 4, 5, 6, 7); deltas = _mm512_and_si512(mask_vec, deltas); __m512i counters = _mm512_add_epi64(_mm512_set1_epi64((int64_t)counter), deltas); *out_lo = _mm512_cvtepi64_epi32(counters); *out_hi = _mm512_cvtepi64_epi32(_mm512_srli_epi64(counters, 32)); } static void blake3_hash8_avx512(const uint8_t *const *inputs, size_t blocks, const uint32_t key[8], uint64_t counter, bool increment_counter, uint8_t flags, uint8_t flags_start, uint8_t flags_end, uint8_t *out) { __m256i h_vecs[8] = { set1_256(key[0]), set1_256(key[1]), set1_256(key[2]), set1_256(key[3]), set1_256(key[4]), set1_256(key[5]), set1_256(key[6]), set1_256(key[7]), }; __m256i counter_low_vec, counter_high_vec; load_counters8(counter, increment_counter, &counter_low_vec, &counter_high_vec); uint8_t block_flags = flags | flags_start; for (size_t block = 0; block < blocks; block++) { if (block + 1 == blocks) { block_flags |= flags_end; } __m256i block_len_vec = set1_256(BLAKE3_BLOCK_LEN); __m256i block_flags_vec = set1_256(block_flags); __m256i msg_vecs[16]; transpose_msg_vecs8(inputs, block * BLAKE3_BLOCK_LEN, msg_vecs); __m256i v[16] = { h_vecs[0], h_vecs[1], h_vecs[2], h_vecs[3], h_vecs[4], h_vecs[5], h_vecs[6], h_vecs[7], set1_256(IV[0]), set1_256(IV[1]), set1_256(IV[2]), set1_256(IV[3]), counter_low_vec, counter_high_vec, block_len_vec, block_flags_vec, }; round_fn8(v, msg_vecs, 0); round_fn8(v, msg_vecs, 1); round_fn8(v, msg_vecs, 2); round_fn8(v, msg_vecs, 3); round_fn8(v, msg_vecs, 4); round_fn8(v, msg_vecs, 5); round_fn8(v, msg_vecs, 6); h_vecs[0] = xor_256(v[0], v[8]); h_vecs[1] = xor_256(v[1], v[9]); h_vecs[2] = xor_256(v[2], v[10]); h_vecs[3] = xor_256(v[3], v[11]); h_vecs[4] = xor_256(v[4], v[12]); h_vecs[5] = xor_256(v[5], v[13]); h_vecs[6] = xor_256(v[6], v[14]); h_vecs[7] = xor_256(v[7], v[15]); block_flags = flags; } transpose_vecs_256(h_vecs); storeu_256(h_vecs[0], &out[0 * sizeof(__m256i)]); storeu_256(h_vecs[1], &out[1 * sizeof(__m256i)]); storeu_256(h_vecs[2], &out[2 * sizeof(__m256i)]); storeu_256(h_vecs[3], &out[3 * sizeof(__m256i)]); storeu_256(h_vecs[4], &out[4 * sizeof(__m256i)]); storeu_256(h_vecs[5], &out[5 * sizeof(__m256i)]); storeu_256(h_vecs[6], &out[6 * sizeof(__m256i)]); storeu_256(h_vecs[7], &out[7 * sizeof(__m256i)]); } static void blake3_xof8_avx512(const uint32_t cv[8], const uint8_t block[BLAKE3_BLOCK_LEN], uint8_t block_len, uint64_t counter, uint8_t flags, uint8_t out[8 * 64]) { __m256i h_vecs[8] = { set1_256(cv[0]), set1_256(cv[1]), set1_256(cv[2]), set1_256(cv[3]), set1_256(cv[4]), set1_256(cv[5]), set1_256(cv[6]), set1_256(cv[7]), }; uint32_t block_words[16]; load_block_words(block, block_words); __m256i msg_vecs[16]; for (size_t i = 0; i < 16; i++) { msg_vecs[i] = set1_256(block_words[i]); } __m256i counter_low_vec, counter_high_vec; load_counters8(counter, true, &counter_low_vec, &counter_high_vec); __m256i block_len_vec = set1_256(block_len); __m256i block_flags_vec = set1_256(flags); __m256i v[16] = { h_vecs[0], h_vecs[1], h_vecs[2], h_vecs[3], h_vecs[4], h_vecs[5], h_vecs[6], h_vecs[7], set1_256(IV[0]), set1_256(IV[1]), set1_256(IV[2]), set1_256(IV[3]), counter_low_vec, counter_high_vec, block_len_vec, block_flags_vec, }; round_fn8(v, msg_vecs, 0); round_fn8(v, msg_vecs, 1); round_fn8(v, msg_vecs, 2); round_fn8(v, msg_vecs, 3); round_fn8(v, msg_vecs, 4); round_fn8(v, msg_vecs, 5); round_fn8(v, msg_vecs, 6); for (size_t i = 0; i < 8; i++) { v[i] = xor_256(v[i], v[i+8]); v[i+8] = xor_256(v[i+8], h_vecs[i]); } transpose_vecs_256(&v[0]); transpose_vecs_256(&v[8]); for (size_t i = 0; i < 8; i++) { storeu_256(v[i+0], &out[(2*i+0) * sizeof(__m256i)]); storeu_256(v[i+8], &out[(2*i+1) * sizeof(__m256i)]); } } /* * ---------------------------------------------------------------------------- * hash16_avx512 * ---------------------------------------------------------------------------- */ INLINE void round_fn16(__m512i v[16], __m512i m[16], size_t r) { v[0] = add_512(v[0], m[(size_t)MSG_SCHEDULE[r][0]]); v[1] = add_512(v[1], m[(size_t)MSG_SCHEDULE[r][2]]); v[2] = add_512(v[2], m[(size_t)MSG_SCHEDULE[r][4]]); v[3] = add_512(v[3], m[(size_t)MSG_SCHEDULE[r][6]]); v[0] = add_512(v[0], v[4]); v[1] = add_512(v[1], v[5]); v[2] = add_512(v[2], v[6]); v[3] = add_512(v[3], v[7]); v[12] = xor_512(v[12], v[0]); v[13] = xor_512(v[13], v[1]); v[14] = xor_512(v[14], v[2]); v[15] = xor_512(v[15], v[3]); v[12] = rot16_512(v[12]); v[13] = rot16_512(v[13]); v[14] = rot16_512(v[14]); v[15] = rot16_512(v[15]); v[8] = add_512(v[8], v[12]); v[9] = add_512(v[9], v[13]); v[10] = add_512(v[10], v[14]); v[11] = add_512(v[11], v[15]); v[4] = xor_512(v[4], v[8]); v[5] = xor_512(v[5], v[9]); v[6] = xor_512(v[6], v[10]); v[7] = xor_512(v[7], v[11]); v[4] = rot12_512(v[4]); v[5] = rot12_512(v[5]); v[6] = rot12_512(v[6]); v[7] = rot12_512(v[7]); v[0] = add_512(v[0], m[(size_t)MSG_SCHEDULE[r][1]]); v[1] = add_512(v[1], m[(size_t)MSG_SCHEDULE[r][3]]); v[2] = add_512(v[2], m[(size_t)MSG_SCHEDULE[r][5]]); v[3] = add_512(v[3], m[(size_t)MSG_SCHEDULE[r][7]]); v[0] = add_512(v[0], v[4]); v[1] = add_512(v[1], v[5]); v[2] = add_512(v[2], v[6]); v[3] = add_512(v[3], v[7]); v[12] = xor_512(v[12], v[0]); v[13] = xor_512(v[13], v[1]); v[14] = xor_512(v[14], v[2]); v[15] = xor_512(v[15], v[3]); v[12] = rot8_512(v[12]); v[13] = rot8_512(v[13]); v[14] = rot8_512(v[14]); v[15] = rot8_512(v[15]); v[8] = add_512(v[8], v[12]); v[9] = add_512(v[9], v[13]); v[10] = add_512(v[10], v[14]); v[11] = add_512(v[11], v[15]); v[4] = xor_512(v[4], v[8]); v[5] = xor_512(v[5], v[9]); v[6] = xor_512(v[6], v[10]); v[7] = xor_512(v[7], v[11]); v[4] = rot7_512(v[4]); v[5] = rot7_512(v[5]); v[6] = rot7_512(v[6]); v[7] = rot7_512(v[7]); v[0] = add_512(v[0], m[(size_t)MSG_SCHEDULE[r][8]]); v[1] = add_512(v[1], m[(size_t)MSG_SCHEDULE[r][10]]); v[2] = add_512(v[2], m[(size_t)MSG_SCHEDULE[r][12]]); v[3] = add_512(v[3], m[(size_t)MSG_SCHEDULE[r][14]]); v[0] = add_512(v[0], v[5]); v[1] = add_512(v[1], v[6]); v[2] = add_512(v[2], v[7]); v[3] = add_512(v[3], v[4]); v[15] = xor_512(v[15], v[0]); v[12] = xor_512(v[12], v[1]); v[13] = xor_512(v[13], v[2]); v[14] = xor_512(v[14], v[3]); v[15] = rot16_512(v[15]); v[12] = rot16_512(v[12]); v[13] = rot16_512(v[13]); v[14] = rot16_512(v[14]); v[10] = add_512(v[10], v[15]); v[11] = add_512(v[11], v[12]); v[8] = add_512(v[8], v[13]); v[9] = add_512(v[9], v[14]); v[5] = xor_512(v[5], v[10]); v[6] = xor_512(v[6], v[11]); v[7] = xor_512(v[7], v[8]); v[4] = xor_512(v[4], v[9]); v[5] = rot12_512(v[5]); v[6] = rot12_512(v[6]); v[7] = rot12_512(v[7]); v[4] = rot12_512(v[4]); v[0] = add_512(v[0], m[(size_t)MSG_SCHEDULE[r][9]]); v[1] = add_512(v[1], m[(size_t)MSG_SCHEDULE[r][11]]); v[2] = add_512(v[2], m[(size_t)MSG_SCHEDULE[r][13]]); v[3] = add_512(v[3], m[(size_t)MSG_SCHEDULE[r][15]]); v[0] = add_512(v[0], v[5]); v[1] = add_512(v[1], v[6]); v[2] = add_512(v[2], v[7]); v[3] = add_512(v[3], v[4]); v[15] = xor_512(v[15], v[0]); v[12] = xor_512(v[12], v[1]); v[13] = xor_512(v[13], v[2]); v[14] = xor_512(v[14], v[3]); v[15] = rot8_512(v[15]); v[12] = rot8_512(v[12]); v[13] = rot8_512(v[13]); v[14] = rot8_512(v[14]); v[10] = add_512(v[10], v[15]); v[11] = add_512(v[11], v[12]); v[8] = add_512(v[8], v[13]); v[9] = add_512(v[9], v[14]); v[5] = xor_512(v[5], v[10]); v[6] = xor_512(v[6], v[11]); v[7] = xor_512(v[7], v[8]); v[4] = xor_512(v[4], v[9]); v[5] = rot7_512(v[5]); v[6] = rot7_512(v[6]); v[7] = rot7_512(v[7]); v[4] = rot7_512(v[4]); } // 0b10001000, or lanes a0/a2/b0/b2 in little-endian order #define LO_IMM8 0x88 INLINE __m512i unpack_lo_128(__m512i a, __m512i b) { return _mm512_shuffle_i32x4(a, b, LO_IMM8); } // 0b11011101, or lanes a1/a3/b1/b3 in little-endian order #define HI_IMM8 0xdd INLINE __m512i unpack_hi_128(__m512i a, __m512i b) { return _mm512_shuffle_i32x4(a, b, HI_IMM8); } INLINE void transpose_vecs_512(__m512i vecs[16]) { // Interleave 32-bit lanes. The _0 unpack is lanes // 0/0/1/1/4/4/5/5/8/8/9/9/12/12/13/13, and the _2 unpack is lanes // 2/2/3/3/6/6/7/7/10/10/11/11/14/14/15/15. __m512i ab_0 = _mm512_unpacklo_epi32(vecs[0], vecs[1]); __m512i ab_2 = _mm512_unpackhi_epi32(vecs[0], vecs[1]); __m512i cd_0 = _mm512_unpacklo_epi32(vecs[2], vecs[3]); __m512i cd_2 = _mm512_unpackhi_epi32(vecs[2], vecs[3]); __m512i ef_0 = _mm512_unpacklo_epi32(vecs[4], vecs[5]); __m512i ef_2 = _mm512_unpackhi_epi32(vecs[4], vecs[5]); __m512i gh_0 = _mm512_unpacklo_epi32(vecs[6], vecs[7]); __m512i gh_2 = _mm512_unpackhi_epi32(vecs[6], vecs[7]); __m512i ij_0 = _mm512_unpacklo_epi32(vecs[8], vecs[9]); __m512i ij_2 = _mm512_unpackhi_epi32(vecs[8], vecs[9]); __m512i kl_0 = _mm512_unpacklo_epi32(vecs[10], vecs[11]); __m512i kl_2 = _mm512_unpackhi_epi32(vecs[10], vecs[11]); __m512i mn_0 = _mm512_unpacklo_epi32(vecs[12], vecs[13]); __m512i mn_2 = _mm512_unpackhi_epi32(vecs[12], vecs[13]); __m512i op_0 = _mm512_unpacklo_epi32(vecs[14], vecs[15]); __m512i op_2 = _mm512_unpackhi_epi32(vecs[14], vecs[15]); // Interleave 64-bit lanes. The _0 unpack is lanes // 0/0/0/0/4/4/4/4/8/8/8/8/12/12/12/12, the _1 unpack is lanes // 1/1/1/1/5/5/5/5/9/9/9/9/13/13/13/13, the _2 unpack is lanes // 2/2/2/2/6/6/6/6/10/10/10/10/14/14/14/14, and the _3 unpack is lanes // 3/3/3/3/7/7/7/7/11/11/11/11/15/15/15/15. __m512i abcd_0 = _mm512_unpacklo_epi64(ab_0, cd_0); __m512i abcd_1 = _mm512_unpackhi_epi64(ab_0, cd_0); __m512i abcd_2 = _mm512_unpacklo_epi64(ab_2, cd_2); __m512i abcd_3 = _mm512_unpackhi_epi64(ab_2, cd_2); __m512i efgh_0 = _mm512_unpacklo_epi64(ef_0, gh_0); __m512i efgh_1 = _mm512_unpackhi_epi64(ef_0, gh_0); __m512i efgh_2 = _mm512_unpacklo_epi64(ef_2, gh_2); __m512i efgh_3 = _mm512_unpackhi_epi64(ef_2, gh_2); __m512i ijkl_0 = _mm512_unpacklo_epi64(ij_0, kl_0); __m512i ijkl_1 = _mm512_unpackhi_epi64(ij_0, kl_0); __m512i ijkl_2 = _mm512_unpacklo_epi64(ij_2, kl_2); __m512i ijkl_3 = _mm512_unpackhi_epi64(ij_2, kl_2); __m512i mnop_0 = _mm512_unpacklo_epi64(mn_0, op_0); __m512i mnop_1 = _mm512_unpackhi_epi64(mn_0, op_0); __m512i mnop_2 = _mm512_unpacklo_epi64(mn_2, op_2); __m512i mnop_3 = _mm512_unpackhi_epi64(mn_2, op_2); // Interleave 128-bit lanes. The _0 unpack is // 0/0/0/0/8/8/8/8/0/0/0/0/8/8/8/8, the _1 unpack is // 1/1/1/1/9/9/9/9/1/1/1/1/9/9/9/9, and so on. __m512i abcdefgh_0 = unpack_lo_128(abcd_0, efgh_0); __m512i abcdefgh_1 = unpack_lo_128(abcd_1, efgh_1); __m512i abcdefgh_2 = unpack_lo_128(abcd_2, efgh_2); __m512i abcdefgh_3 = unpack_lo_128(abcd_3, efgh_3); __m512i abcdefgh_4 = unpack_hi_128(abcd_0, efgh_0); __m512i abcdefgh_5 = unpack_hi_128(abcd_1, efgh_1); __m512i abcdefgh_6 = unpack_hi_128(abcd_2, efgh_2); __m512i abcdefgh_7 = unpack_hi_128(abcd_3, efgh_3); __m512i ijklmnop_0 = unpack_lo_128(ijkl_0, mnop_0); __m512i ijklmnop_1 = unpack_lo_128(ijkl_1, mnop_1); __m512i ijklmnop_2 = unpack_lo_128(ijkl_2, mnop_2); __m512i ijklmnop_3 = unpack_lo_128(ijkl_3, mnop_3); __m512i ijklmnop_4 = unpack_hi_128(ijkl_0, mnop_0); __m512i ijklmnop_5 = unpack_hi_128(ijkl_1, mnop_1); __m512i ijklmnop_6 = unpack_hi_128(ijkl_2, mnop_2); __m512i ijklmnop_7 = unpack_hi_128(ijkl_3, mnop_3); // Interleave 128-bit lanes again for the final outputs. vecs[0] = unpack_lo_128(abcdefgh_0, ijklmnop_0); vecs[1] = unpack_lo_128(abcdefgh_1, ijklmnop_1); vecs[2] = unpack_lo_128(abcdefgh_2, ijklmnop_2); vecs[3] = unpack_lo_128(abcdefgh_3, ijklmnop_3); vecs[4] = unpack_lo_128(abcdefgh_4, ijklmnop_4); vecs[5] = unpack_lo_128(abcdefgh_5, ijklmnop_5); vecs[6] = unpack_lo_128(abcdefgh_6, ijklmnop_6); vecs[7] = unpack_lo_128(abcdefgh_7, ijklmnop_7); vecs[8] = unpack_hi_128(abcdefgh_0, ijklmnop_0); vecs[9] = unpack_hi_128(abcdefgh_1, ijklmnop_1); vecs[10] = unpack_hi_128(abcdefgh_2, ijklmnop_2); vecs[11] = unpack_hi_128(abcdefgh_3, ijklmnop_3); vecs[12] = unpack_hi_128(abcdefgh_4, ijklmnop_4); vecs[13] = unpack_hi_128(abcdefgh_5, ijklmnop_5); vecs[14] = unpack_hi_128(abcdefgh_6, ijklmnop_6); vecs[15] = unpack_hi_128(abcdefgh_7, ijklmnop_7); } INLINE void transpose_msg_vecs16(const uint8_t *const *inputs, size_t block_offset, __m512i out[16]) { out[0] = loadu_512(&inputs[0][block_offset]); out[1] = loadu_512(&inputs[1][block_offset]); out[2] = loadu_512(&inputs[2][block_offset]); out[3] = loadu_512(&inputs[3][block_offset]); out[4] = loadu_512(&inputs[4][block_offset]); out[5] = loadu_512(&inputs[5][block_offset]); out[6] = loadu_512(&inputs[6][block_offset]); out[7] = loadu_512(&inputs[7][block_offset]); out[8] = loadu_512(&inputs[8][block_offset]); out[9] = loadu_512(&inputs[9][block_offset]); out[10] = loadu_512(&inputs[10][block_offset]); out[11] = loadu_512(&inputs[11][block_offset]); out[12] = loadu_512(&inputs[12][block_offset]); out[13] = loadu_512(&inputs[13][block_offset]); out[14] = loadu_512(&inputs[14][block_offset]); out[15] = loadu_512(&inputs[15][block_offset]); for (size_t i = 0; i < 16; ++i) { _mm_prefetch((const void *)&inputs[i][block_offset + 256], _MM_HINT_T0); } transpose_vecs_512(out); } INLINE void load_counters16(uint64_t counter, bool increment_counter, __m512i *out_lo, __m512i *out_hi) { const __m512i mask = _mm512_set1_epi32(-(int32_t)increment_counter); const __m512i deltas = _mm512_set_epi32(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0); const __m512i masked_deltas = _mm512_and_si512(deltas, mask); const __m512i low_words = _mm512_add_epi32( _mm512_set1_epi32((int32_t)counter), masked_deltas); // The carry bit is 1 if the high bit of the word was 1 before addition and is // 0 after. // NOTE: It would be a bit more natural to use _mm512_cmp_epu32_mask to // compute the carry bits here, and originally we did, but that intrinsic is // broken under GCC 5.4. See https://github.com/BLAKE3-team/BLAKE3/issues/271. const __m512i carries = _mm512_srli_epi32( _mm512_andnot_si512( low_words, // 0 after (gets inverted by andnot) _mm512_set1_epi32((int32_t)counter)), // and 1 before 31); const __m512i high_words = _mm512_add_epi32( _mm512_set1_epi32((int32_t)(counter >> 32)), carries); *out_lo = low_words; *out_hi = high_words; } static void blake3_hash16_avx512(const uint8_t *const *inputs, size_t blocks, const uint32_t key[8], uint64_t counter, bool increment_counter, uint8_t flags, uint8_t flags_start, uint8_t flags_end, uint8_t *out) { __m512i h_vecs[8] = { set1_512(key[0]), set1_512(key[1]), set1_512(key[2]), set1_512(key[3]), set1_512(key[4]), set1_512(key[5]), set1_512(key[6]), set1_512(key[7]), }; __m512i counter_low_vec, counter_high_vec; load_counters16(counter, increment_counter, &counter_low_vec, &counter_high_vec); uint8_t block_flags = flags | flags_start; for (size_t block = 0; block < blocks; block++) { if (block + 1 == blocks) { block_flags |= flags_end; } __m512i block_len_vec = set1_512(BLAKE3_BLOCK_LEN); __m512i block_flags_vec = set1_512(block_flags); __m512i msg_vecs[16]; transpose_msg_vecs16(inputs, block * BLAKE3_BLOCK_LEN, msg_vecs); __m512i v[16] = { h_vecs[0], h_vecs[1], h_vecs[2], h_vecs[3], h_vecs[4], h_vecs[5], h_vecs[6], h_vecs[7], set1_512(IV[0]), set1_512(IV[1]), set1_512(IV[2]), set1_512(IV[3]), counter_low_vec, counter_high_vec, block_len_vec, block_flags_vec, }; round_fn16(v, msg_vecs, 0); round_fn16(v, msg_vecs, 1); round_fn16(v, msg_vecs, 2); round_fn16(v, msg_vecs, 3); round_fn16(v, msg_vecs, 4); round_fn16(v, msg_vecs, 5); round_fn16(v, msg_vecs, 6); h_vecs[0] = xor_512(v[0], v[8]); h_vecs[1] = xor_512(v[1], v[9]); h_vecs[2] = xor_512(v[2], v[10]); h_vecs[3] = xor_512(v[3], v[11]); h_vecs[4] = xor_512(v[4], v[12]); h_vecs[5] = xor_512(v[5], v[13]); h_vecs[6] = xor_512(v[6], v[14]); h_vecs[7] = xor_512(v[7], v[15]); block_flags = flags; } // transpose_vecs_512 operates on a 16x16 matrix of words, but we only have 8 // state vectors. Pad the matrix with zeros. After transposition, store the // lower half of each vector. __m512i padded[16] = { h_vecs[0], h_vecs[1], h_vecs[2], h_vecs[3], h_vecs[4], h_vecs[5], h_vecs[6], h_vecs[7], set1_512(0), set1_512(0), set1_512(0), set1_512(0), set1_512(0), set1_512(0), set1_512(0), set1_512(0), }; transpose_vecs_512(padded); _mm256_mask_storeu_epi32(&out[0 * sizeof(__m256i)], (__mmask8)-1, _mm512_castsi512_si256(padded[0])); _mm256_mask_storeu_epi32(&out[1 * sizeof(__m256i)], (__mmask8)-1, _mm512_castsi512_si256(padded[1])); _mm256_mask_storeu_epi32(&out[2 * sizeof(__m256i)], (__mmask8)-1, _mm512_castsi512_si256(padded[2])); _mm256_mask_storeu_epi32(&out[3 * sizeof(__m256i)], (__mmask8)-1, _mm512_castsi512_si256(padded[3])); _mm256_mask_storeu_epi32(&out[4 * sizeof(__m256i)], (__mmask8)-1, _mm512_castsi512_si256(padded[4])); _mm256_mask_storeu_epi32(&out[5 * sizeof(__m256i)], (__mmask8)-1, _mm512_castsi512_si256(padded[5])); _mm256_mask_storeu_epi32(&out[6 * sizeof(__m256i)], (__mmask8)-1, _mm512_castsi512_si256(padded[6])); _mm256_mask_storeu_epi32(&out[7 * sizeof(__m256i)], (__mmask8)-1, _mm512_castsi512_si256(padded[7])); _mm256_mask_storeu_epi32(&out[8 * sizeof(__m256i)], (__mmask8)-1, _mm512_castsi512_si256(padded[8])); _mm256_mask_storeu_epi32(&out[9 * sizeof(__m256i)], (__mmask8)-1, _mm512_castsi512_si256(padded[9])); _mm256_mask_storeu_epi32(&out[10 * sizeof(__m256i)], (__mmask8)-1, _mm512_castsi512_si256(padded[10])); _mm256_mask_storeu_epi32(&out[11 * sizeof(__m256i)], (__mmask8)-1, _mm512_castsi512_si256(padded[11])); _mm256_mask_storeu_epi32(&out[12 * sizeof(__m256i)], (__mmask8)-1, _mm512_castsi512_si256(padded[12])); _mm256_mask_storeu_epi32(&out[13 * sizeof(__m256i)], (__mmask8)-1, _mm512_castsi512_si256(padded[13])); _mm256_mask_storeu_epi32(&out[14 * sizeof(__m256i)], (__mmask8)-1, _mm512_castsi512_si256(padded[14])); _mm256_mask_storeu_epi32(&out[15 * sizeof(__m256i)], (__mmask8)-1, _mm512_castsi512_si256(padded[15])); } static void blake3_xof16_avx512(const uint32_t cv[8], const uint8_t block[BLAKE3_BLOCK_LEN], uint8_t block_len, uint64_t counter, uint8_t flags, uint8_t out[16 * 64]) { __m512i h_vecs[8] = { set1_512(cv[0]), set1_512(cv[1]), set1_512(cv[2]), set1_512(cv[3]), set1_512(cv[4]), set1_512(cv[5]), set1_512(cv[6]), set1_512(cv[7]), }; uint32_t block_words[16]; load_block_words(block, block_words); __m512i msg_vecs[16]; for (size_t i = 0; i < 16; i++) { msg_vecs[i] = set1_512(block_words[i]); } __m512i counter_low_vec, counter_high_vec; load_counters16(counter, true, &counter_low_vec, &counter_high_vec); __m512i block_len_vec = set1_512(block_len); __m512i block_flags_vec = set1_512(flags); __m512i v[16] = { h_vecs[0], h_vecs[1], h_vecs[2], h_vecs[3], h_vecs[4], h_vecs[5], h_vecs[6], h_vecs[7], set1_512(IV[0]), set1_512(IV[1]), set1_512(IV[2]), set1_512(IV[3]), counter_low_vec, counter_high_vec, block_len_vec, block_flags_vec, }; round_fn16(v, msg_vecs, 0); round_fn16(v, msg_vecs, 1); round_fn16(v, msg_vecs, 2); round_fn16(v, msg_vecs, 3); round_fn16(v, msg_vecs, 4); round_fn16(v, msg_vecs, 5); round_fn16(v, msg_vecs, 6); for (size_t i = 0; i < 8; i++) { v[i] = xor_512(v[i], v[i+8]); v[i+8] = xor_512(v[i+8], h_vecs[i]); } transpose_vecs_512(&v[0]); for (size_t i = 0; i < 16; i++) { storeu_512(v[i], &out[i * sizeof(__m512i)]); } } /* * ---------------------------------------------------------------------------- * hash_many_avx512 * ---------------------------------------------------------------------------- */ INLINE void hash_one_avx512(const uint8_t *input, size_t blocks, const uint32_t key[8], uint64_t counter, uint8_t flags, uint8_t flags_start, uint8_t flags_end, uint8_t out[BLAKE3_OUT_LEN]) { uint32_t cv[8]; memcpy(cv, key, BLAKE3_KEY_LEN); uint8_t block_flags = flags | flags_start; while (blocks > 0) { if (blocks == 1) { block_flags |= flags_end; } blake3_compress_in_place_avx512(cv, input, BLAKE3_BLOCK_LEN, counter, block_flags); input = &input[BLAKE3_BLOCK_LEN]; blocks -= 1; block_flags = flags; } memcpy(out, cv, BLAKE3_OUT_LEN); } void blake3_hash_many_avx512(const uint8_t *const *inputs, size_t num_inputs, size_t blocks, const uint32_t key[8], uint64_t counter, bool increment_counter, uint8_t flags, uint8_t flags_start, uint8_t flags_end, uint8_t *out) { while (num_inputs >= 16) { blake3_hash16_avx512(inputs, blocks, key, counter, increment_counter, flags, flags_start, flags_end, out); if (increment_counter) { counter += 16; } inputs += 16; num_inputs -= 16; out = &out[16 * BLAKE3_OUT_LEN]; } while (num_inputs >= 8) { blake3_hash8_avx512(inputs, blocks, key, counter, increment_counter, flags, flags_start, flags_end, out); if (increment_counter) { counter += 8; } inputs += 8; num_inputs -= 8; out = &out[8 * BLAKE3_OUT_LEN]; } while (num_inputs >= 4) { blake3_hash4_avx512(inputs, blocks, key, counter, increment_counter, flags, flags_start, flags_end, out); if (increment_counter) { counter += 4; } inputs += 4; num_inputs -= 4; out = &out[4 * BLAKE3_OUT_LEN]; } while (num_inputs > 0) { hash_one_avx512(inputs[0], blocks, key, counter, flags, flags_start, flags_end, out); if (increment_counter) { counter += 1; } inputs += 1; num_inputs -= 1; out = &out[BLAKE3_OUT_LEN]; } } void blake3_xof_many_avx512(const uint32_t cv[8], const uint8_t block[BLAKE3_BLOCK_LEN], uint8_t block_len, uint64_t counter, uint8_t flags, uint8_t* out, size_t outblocks) { while (outblocks >= 16) { blake3_xof16_avx512(cv, block, block_len, counter, flags, out); counter += 16; outblocks -= 16; out += 16 * BLAKE3_BLOCK_LEN; } while (outblocks >= 8) { blake3_xof8_avx512(cv, block, block_len, counter, flags, out); counter += 8; outblocks -= 8; out += 8 * BLAKE3_BLOCK_LEN; } while (outblocks >= 4) { blake3_xof4_avx512(cv, block, block_len, counter, flags, out); counter += 4; outblocks -= 4; out += 4 * BLAKE3_BLOCK_LEN; } while (outblocks > 0) { blake3_compress_xof_avx512(cv, block, block_len, counter, flags, out); counter += 1; outblocks -= 1; out += BLAKE3_BLOCK_LEN; } } librecast/libs/blake3/c/blake3_avx512_x86-64_unix.S000066400000000000000000004736101502456746400217640ustar00rootroot00000000000000#if defined(__ELF__) && defined(__linux__) .section .note.GNU-stack,"",%progbits #endif #if defined(__ELF__) && defined(__CET__) && defined(__has_include) #if __has_include() #include #endif #endif #if !defined(_CET_ENDBR) #define _CET_ENDBR #endif .intel_syntax noprefix .global _blake3_hash_many_avx512 .global blake3_hash_many_avx512 .global blake3_compress_in_place_avx512 .global _blake3_compress_in_place_avx512 .global blake3_compress_xof_avx512 .global _blake3_compress_xof_avx512 .global blake3_xof_many_avx512 .global _blake3_xof_many_avx512 #ifdef __APPLE__ .text #else .section .text #endif .p2align 6 _blake3_hash_many_avx512: blake3_hash_many_avx512: _CET_ENDBR push r15 push r14 push r13 push r12 push rbx push rbp mov rbp, rsp sub rsp, 144 and rsp, 0xFFFFFFFFFFFFFFC0 neg r9 kmovw k1, r9d vmovd xmm0, r8d vpbroadcastd ymm0, xmm0 shr r8, 32 vmovd xmm1, r8d vpbroadcastd ymm1, xmm1 vmovdqa ymm4, ymm1 vmovdqa ymm5, ymm1 vpaddd ymm2, ymm0, ymmword ptr [ADD0+rip] vpaddd ymm3, ymm0, ymmword ptr [ADD0+32+rip] vpcmpltud k2, ymm2, ymm0 vpcmpltud k3, ymm3, ymm0 vpaddd ymm4 {k2}, ymm4, dword ptr [ADD1+rip] {1to8} vpaddd ymm5 {k3}, ymm5, dword ptr [ADD1+rip] {1to8} knotw k2, k1 vmovdqa32 ymm2 {k2}, ymm0 vmovdqa32 ymm3 {k2}, ymm0 vmovdqa32 ymm4 {k2}, ymm1 vmovdqa32 ymm5 {k2}, ymm1 vmovdqa ymmword ptr [rsp], ymm2 vmovdqa ymmword ptr [rsp+0x1*0x20], ymm3 vmovdqa ymmword ptr [rsp+0x2*0x20], ymm4 vmovdqa ymmword ptr [rsp+0x3*0x20], ymm5 shl rdx, 6 mov qword ptr [rsp+0x80], rdx cmp rsi, 16 jc 3f 2: vpbroadcastd zmm0, dword ptr [rcx] vpbroadcastd zmm1, dword ptr [rcx+0x1*0x4] vpbroadcastd zmm2, dword ptr [rcx+0x2*0x4] vpbroadcastd zmm3, dword ptr [rcx+0x3*0x4] vpbroadcastd zmm4, dword ptr [rcx+0x4*0x4] vpbroadcastd zmm5, dword ptr [rcx+0x5*0x4] vpbroadcastd zmm6, dword ptr [rcx+0x6*0x4] vpbroadcastd zmm7, dword ptr [rcx+0x7*0x4] movzx eax, byte ptr [rbp+0x38] movzx ebx, byte ptr [rbp+0x40] or eax, ebx xor edx, edx .p2align 5 9: movzx ebx, byte ptr [rbp+0x48] or ebx, eax add rdx, 64 cmp rdx, qword ptr [rsp+0x80] cmove eax, ebx mov dword ptr [rsp+0x88], eax mov r8, qword ptr [rdi] mov r9, qword ptr [rdi+0x8] mov r10, qword ptr [rdi+0x10] mov r11, qword ptr [rdi+0x18] mov r12, qword ptr [rdi+0x40] mov r13, qword ptr [rdi+0x48] mov r14, qword ptr [rdi+0x50] mov r15, qword ptr [rdi+0x58] vmovdqu32 ymm16, ymmword ptr [rdx+r8-0x2*0x20] vinserti64x4 zmm16, zmm16, ymmword ptr [rdx+r12-0x2*0x20], 0x01 vmovdqu32 ymm17, ymmword ptr [rdx+r9-0x2*0x20] vinserti64x4 zmm17, zmm17, ymmword ptr [rdx+r13-0x2*0x20], 0x01 vpunpcklqdq zmm8, zmm16, zmm17 vpunpckhqdq zmm9, zmm16, zmm17 vmovdqu32 ymm18, ymmword ptr [rdx+r10-0x2*0x20] vinserti64x4 zmm18, zmm18, ymmword ptr [rdx+r14-0x2*0x20], 0x01 vmovdqu32 ymm19, ymmword ptr [rdx+r11-0x2*0x20] vinserti64x4 zmm19, zmm19, ymmword ptr [rdx+r15-0x2*0x20], 0x01 vpunpcklqdq zmm10, zmm18, zmm19 vpunpckhqdq zmm11, zmm18, zmm19 mov r8, qword ptr [rdi+0x20] mov r9, qword ptr [rdi+0x28] mov r10, qword ptr [rdi+0x30] mov r11, qword ptr [rdi+0x38] mov r12, qword ptr [rdi+0x60] mov r13, qword ptr [rdi+0x68] mov r14, qword ptr [rdi+0x70] mov r15, qword ptr [rdi+0x78] vmovdqu32 ymm16, ymmword ptr [rdx+r8-0x2*0x20] vinserti64x4 zmm16, zmm16, ymmword ptr [rdx+r12-0x2*0x20], 0x01 vmovdqu32 ymm17, ymmword ptr [rdx+r9-0x2*0x20] vinserti64x4 zmm17, zmm17, ymmword ptr [rdx+r13-0x2*0x20], 0x01 vpunpcklqdq zmm12, zmm16, zmm17 vpunpckhqdq zmm13, zmm16, zmm17 vmovdqu32 ymm18, ymmword ptr [rdx+r10-0x2*0x20] vinserti64x4 zmm18, zmm18, ymmword ptr [rdx+r14-0x2*0x20], 0x01 vmovdqu32 ymm19, ymmword ptr [rdx+r11-0x2*0x20] vinserti64x4 zmm19, zmm19, ymmword ptr [rdx+r15-0x2*0x20], 0x01 vpunpcklqdq zmm14, zmm18, zmm19 vpunpckhqdq zmm15, zmm18, zmm19 vmovdqa32 zmm27, zmmword ptr [INDEX0+rip] vmovdqa32 zmm31, zmmword ptr [INDEX1+rip] vshufps zmm16, zmm8, zmm10, 136 vshufps zmm17, zmm12, zmm14, 136 vmovdqa32 zmm20, zmm16 vpermt2d zmm16, zmm27, zmm17 vpermt2d zmm20, zmm31, zmm17 vshufps zmm17, zmm8, zmm10, 221 vshufps zmm30, zmm12, zmm14, 221 vmovdqa32 zmm21, zmm17 vpermt2d zmm17, zmm27, zmm30 vpermt2d zmm21, zmm31, zmm30 vshufps zmm18, zmm9, zmm11, 136 vshufps zmm8, zmm13, zmm15, 136 vmovdqa32 zmm22, zmm18 vpermt2d zmm18, zmm27, zmm8 vpermt2d zmm22, zmm31, zmm8 vshufps zmm19, zmm9, zmm11, 221 vshufps zmm8, zmm13, zmm15, 221 vmovdqa32 zmm23, zmm19 vpermt2d zmm19, zmm27, zmm8 vpermt2d zmm23, zmm31, zmm8 mov r8, qword ptr [rdi] mov r9, qword ptr [rdi+0x8] mov r10, qword ptr [rdi+0x10] mov r11, qword ptr [rdi+0x18] mov r12, qword ptr [rdi+0x40] mov r13, qword ptr [rdi+0x48] mov r14, qword ptr [rdi+0x50] mov r15, qword ptr [rdi+0x58] vmovdqu32 ymm24, ymmword ptr [r8+rdx-0x1*0x20] vinserti64x4 zmm24, zmm24, ymmword ptr [r12+rdx-0x1*0x20], 0x01 vmovdqu32 ymm25, ymmword ptr [r9+rdx-0x1*0x20] vinserti64x4 zmm25, zmm25, ymmword ptr [r13+rdx-0x1*0x20], 0x01 vpunpcklqdq zmm8, zmm24, zmm25 vpunpckhqdq zmm9, zmm24, zmm25 vmovdqu32 ymm24, ymmword ptr [r10+rdx-0x1*0x20] vinserti64x4 zmm24, zmm24, ymmword ptr [r14+rdx-0x1*0x20], 0x01 vmovdqu32 ymm25, ymmword ptr [r11+rdx-0x1*0x20] vinserti64x4 zmm25, zmm25, ymmword ptr [r15+rdx-0x1*0x20], 0x01 vpunpcklqdq zmm10, zmm24, zmm25 vpunpckhqdq zmm11, zmm24, zmm25 prefetcht0 [r8+rdx+0x80] prefetcht0 [r12+rdx+0x80] prefetcht0 [r9+rdx+0x80] prefetcht0 [r13+rdx+0x80] prefetcht0 [r10+rdx+0x80] prefetcht0 [r14+rdx+0x80] prefetcht0 [r11+rdx+0x80] prefetcht0 [r15+rdx+0x80] mov r8, qword ptr [rdi+0x20] mov r9, qword ptr [rdi+0x28] mov r10, qword ptr [rdi+0x30] mov r11, qword ptr [rdi+0x38] mov r12, qword ptr [rdi+0x60] mov r13, qword ptr [rdi+0x68] mov r14, qword ptr [rdi+0x70] mov r15, qword ptr [rdi+0x78] vmovdqu32 ymm24, ymmword ptr [r8+rdx-0x1*0x20] vinserti64x4 zmm24, zmm24, ymmword ptr [r12+rdx-0x1*0x20], 0x01 vmovdqu32 ymm25, ymmword ptr [r9+rdx-0x1*0x20] vinserti64x4 zmm25, zmm25, ymmword ptr [r13+rdx-0x1*0x20], 0x01 vpunpcklqdq zmm12, zmm24, zmm25 vpunpckhqdq zmm13, zmm24, zmm25 vmovdqu32 ymm24, ymmword ptr [r10+rdx-0x1*0x20] vinserti64x4 zmm24, zmm24, ymmword ptr [r14+rdx-0x1*0x20], 0x01 vmovdqu32 ymm25, ymmword ptr [r11+rdx-0x1*0x20] vinserti64x4 zmm25, zmm25, ymmword ptr [r15+rdx-0x1*0x20], 0x01 vpunpcklqdq zmm14, zmm24, zmm25 vpunpckhqdq zmm15, zmm24, zmm25 prefetcht0 [r8+rdx+0x80] prefetcht0 [r12+rdx+0x80] prefetcht0 [r9+rdx+0x80] prefetcht0 [r13+rdx+0x80] prefetcht0 [r10+rdx+0x80] prefetcht0 [r14+rdx+0x80] prefetcht0 [r11+rdx+0x80] prefetcht0 [r15+rdx+0x80] vshufps zmm24, zmm8, zmm10, 136 vshufps zmm30, zmm12, zmm14, 136 vmovdqa32 zmm28, zmm24 vpermt2d zmm24, zmm27, zmm30 vpermt2d zmm28, zmm31, zmm30 vshufps zmm25, zmm8, zmm10, 221 vshufps zmm30, zmm12, zmm14, 221 vmovdqa32 zmm29, zmm25 vpermt2d zmm25, zmm27, zmm30 vpermt2d zmm29, zmm31, zmm30 vshufps zmm26, zmm9, zmm11, 136 vshufps zmm8, zmm13, zmm15, 136 vmovdqa32 zmm30, zmm26 vpermt2d zmm26, zmm27, zmm8 vpermt2d zmm30, zmm31, zmm8 vshufps zmm8, zmm9, zmm11, 221 vshufps zmm10, zmm13, zmm15, 221 vpermi2d zmm27, zmm8, zmm10 vpermi2d zmm31, zmm8, zmm10 vpbroadcastd zmm8, dword ptr [BLAKE3_IV_0+rip] vpbroadcastd zmm9, dword ptr [BLAKE3_IV_1+rip] vpbroadcastd zmm10, dword ptr [BLAKE3_IV_2+rip] vpbroadcastd zmm11, dword ptr [BLAKE3_IV_3+rip] vmovdqa32 zmm12, zmmword ptr [rsp] vmovdqa32 zmm13, zmmword ptr [rsp+0x1*0x40] vpbroadcastd zmm14, dword ptr [BLAKE3_BLOCK_LEN+rip] vpbroadcastd zmm15, dword ptr [rsp+0x22*0x4] vpaddd zmm0, zmm0, zmm16 vpaddd zmm1, zmm1, zmm18 vpaddd zmm2, zmm2, zmm20 vpaddd zmm3, zmm3, zmm22 vpaddd zmm0, zmm0, zmm4 vpaddd zmm1, zmm1, zmm5 vpaddd zmm2, zmm2, zmm6 vpaddd zmm3, zmm3, zmm7 vpxord zmm12, zmm12, zmm0 vpxord zmm13, zmm13, zmm1 vpxord zmm14, zmm14, zmm2 vpxord zmm15, zmm15, zmm3 vprord zmm12, zmm12, 16 vprord zmm13, zmm13, 16 vprord zmm14, zmm14, 16 vprord zmm15, zmm15, 16 vpaddd zmm8, zmm8, zmm12 vpaddd zmm9, zmm9, zmm13 vpaddd zmm10, zmm10, zmm14 vpaddd zmm11, zmm11, zmm15 vpxord zmm4, zmm4, zmm8 vpxord zmm5, zmm5, zmm9 vpxord zmm6, zmm6, zmm10 vpxord zmm7, zmm7, zmm11 vprord zmm4, zmm4, 12 vprord zmm5, zmm5, 12 vprord zmm6, zmm6, 12 vprord zmm7, zmm7, 12 vpaddd zmm0, zmm0, zmm17 vpaddd zmm1, zmm1, zmm19 vpaddd zmm2, zmm2, zmm21 vpaddd zmm3, zmm3, zmm23 vpaddd zmm0, zmm0, zmm4 vpaddd zmm1, zmm1, zmm5 vpaddd zmm2, zmm2, zmm6 vpaddd zmm3, zmm3, zmm7 vpxord zmm12, zmm12, zmm0 vpxord zmm13, zmm13, zmm1 vpxord zmm14, zmm14, zmm2 vpxord zmm15, zmm15, zmm3 vprord zmm12, zmm12, 8 vprord zmm13, zmm13, 8 vprord zmm14, zmm14, 8 vprord zmm15, zmm15, 8 vpaddd zmm8, zmm8, zmm12 vpaddd zmm9, zmm9, zmm13 vpaddd zmm10, zmm10, zmm14 vpaddd zmm11, zmm11, zmm15 vpxord zmm4, zmm4, zmm8 vpxord zmm5, zmm5, zmm9 vpxord zmm6, zmm6, zmm10 vpxord zmm7, zmm7, zmm11 vprord zmm4, zmm4, 7 vprord zmm5, zmm5, 7 vprord zmm6, zmm6, 7 vprord zmm7, zmm7, 7 vpaddd zmm0, zmm0, zmm24 vpaddd zmm1, zmm1, zmm26 vpaddd zmm2, zmm2, zmm28 vpaddd zmm3, zmm3, zmm30 vpaddd zmm0, zmm0, zmm5 vpaddd zmm1, zmm1, zmm6 vpaddd zmm2, zmm2, zmm7 vpaddd zmm3, zmm3, zmm4 vpxord zmm15, zmm15, zmm0 vpxord zmm12, zmm12, zmm1 vpxord zmm13, zmm13, zmm2 vpxord zmm14, zmm14, zmm3 vprord zmm15, zmm15, 16 vprord zmm12, zmm12, 16 vprord zmm13, zmm13, 16 vprord zmm14, zmm14, 16 vpaddd zmm10, zmm10, zmm15 vpaddd zmm11, zmm11, zmm12 vpaddd zmm8, zmm8, zmm13 vpaddd zmm9, zmm9, zmm14 vpxord zmm5, zmm5, zmm10 vpxord zmm6, zmm6, zmm11 vpxord zmm7, zmm7, zmm8 vpxord zmm4, zmm4, zmm9 vprord zmm5, zmm5, 12 vprord zmm6, zmm6, 12 vprord zmm7, zmm7, 12 vprord zmm4, zmm4, 12 vpaddd zmm0, zmm0, zmm25 vpaddd zmm1, zmm1, zmm27 vpaddd zmm2, zmm2, zmm29 vpaddd zmm3, zmm3, zmm31 vpaddd zmm0, zmm0, zmm5 vpaddd zmm1, zmm1, zmm6 vpaddd zmm2, zmm2, zmm7 vpaddd zmm3, zmm3, zmm4 vpxord zmm15, zmm15, zmm0 vpxord zmm12, zmm12, zmm1 vpxord zmm13, zmm13, zmm2 vpxord zmm14, zmm14, zmm3 vprord zmm15, zmm15, 8 vprord zmm12, zmm12, 8 vprord zmm13, zmm13, 8 vprord zmm14, zmm14, 8 vpaddd zmm10, zmm10, zmm15 vpaddd zmm11, zmm11, zmm12 vpaddd zmm8, zmm8, zmm13 vpaddd zmm9, zmm9, zmm14 vpxord zmm5, zmm5, zmm10 vpxord zmm6, zmm6, zmm11 vpxord zmm7, zmm7, zmm8 vpxord zmm4, zmm4, zmm9 vprord zmm5, zmm5, 7 vprord zmm6, zmm6, 7 vprord zmm7, zmm7, 7 vprord zmm4, zmm4, 7 vpaddd zmm0, zmm0, zmm18 vpaddd zmm1, zmm1, zmm19 vpaddd zmm2, zmm2, zmm23 vpaddd zmm3, zmm3, zmm20 vpaddd zmm0, zmm0, zmm4 vpaddd zmm1, zmm1, zmm5 vpaddd zmm2, zmm2, zmm6 vpaddd zmm3, zmm3, zmm7 vpxord zmm12, zmm12, zmm0 vpxord zmm13, zmm13, zmm1 vpxord zmm14, zmm14, zmm2 vpxord zmm15, zmm15, zmm3 vprord zmm12, zmm12, 16 vprord zmm13, zmm13, 16 vprord zmm14, zmm14, 16 vprord zmm15, zmm15, 16 vpaddd zmm8, zmm8, zmm12 vpaddd zmm9, zmm9, zmm13 vpaddd zmm10, zmm10, zmm14 vpaddd zmm11, zmm11, zmm15 vpxord zmm4, zmm4, zmm8 vpxord zmm5, zmm5, zmm9 vpxord zmm6, zmm6, zmm10 vpxord zmm7, zmm7, zmm11 vprord zmm4, zmm4, 12 vprord zmm5, zmm5, 12 vprord zmm6, zmm6, 12 vprord zmm7, zmm7, 12 vpaddd zmm0, zmm0, zmm22 vpaddd zmm1, zmm1, zmm26 vpaddd zmm2, zmm2, zmm16 vpaddd zmm3, zmm3, zmm29 vpaddd zmm0, zmm0, zmm4 vpaddd zmm1, zmm1, zmm5 vpaddd zmm2, zmm2, zmm6 vpaddd zmm3, zmm3, zmm7 vpxord zmm12, zmm12, zmm0 vpxord zmm13, zmm13, zmm1 vpxord zmm14, zmm14, zmm2 vpxord zmm15, zmm15, zmm3 vprord zmm12, zmm12, 8 vprord zmm13, zmm13, 8 vprord zmm14, zmm14, 8 vprord zmm15, zmm15, 8 vpaddd zmm8, zmm8, zmm12 vpaddd zmm9, zmm9, zmm13 vpaddd zmm10, zmm10, zmm14 vpaddd zmm11, zmm11, zmm15 vpxord zmm4, zmm4, zmm8 vpxord zmm5, zmm5, zmm9 vpxord zmm6, zmm6, zmm10 vpxord zmm7, zmm7, zmm11 vprord zmm4, zmm4, 7 vprord zmm5, zmm5, 7 vprord zmm6, zmm6, 7 vprord zmm7, zmm7, 7 vpaddd zmm0, zmm0, zmm17 vpaddd zmm1, zmm1, zmm28 vpaddd zmm2, zmm2, zmm25 vpaddd zmm3, zmm3, zmm31 vpaddd zmm0, zmm0, zmm5 vpaddd zmm1, zmm1, zmm6 vpaddd zmm2, zmm2, zmm7 vpaddd zmm3, zmm3, zmm4 vpxord zmm15, zmm15, zmm0 vpxord zmm12, zmm12, zmm1 vpxord zmm13, zmm13, zmm2 vpxord zmm14, zmm14, zmm3 vprord zmm15, zmm15, 16 vprord zmm12, zmm12, 16 vprord zmm13, zmm13, 16 vprord zmm14, zmm14, 16 vpaddd zmm10, zmm10, zmm15 vpaddd zmm11, zmm11, zmm12 vpaddd zmm8, zmm8, zmm13 vpaddd zmm9, zmm9, zmm14 vpxord zmm5, zmm5, zmm10 vpxord zmm6, zmm6, zmm11 vpxord zmm7, zmm7, zmm8 vpxord zmm4, zmm4, zmm9 vprord zmm5, zmm5, 12 vprord zmm6, zmm6, 12 vprord zmm7, zmm7, 12 vprord zmm4, zmm4, 12 vpaddd zmm0, zmm0, zmm27 vpaddd zmm1, zmm1, zmm21 vpaddd zmm2, zmm2, zmm30 vpaddd zmm3, zmm3, zmm24 vpaddd zmm0, zmm0, zmm5 vpaddd zmm1, zmm1, zmm6 vpaddd zmm2, zmm2, zmm7 vpaddd zmm3, zmm3, zmm4 vpxord zmm15, zmm15, zmm0 vpxord zmm12, zmm12, zmm1 vpxord zmm13, zmm13, zmm2 vpxord zmm14, zmm14, zmm3 vprord zmm15, zmm15, 8 vprord zmm12, zmm12, 8 vprord zmm13, zmm13, 8 vprord zmm14, zmm14, 8 vpaddd zmm10, zmm10, zmm15 vpaddd zmm11, zmm11, zmm12 vpaddd zmm8, zmm8, zmm13 vpaddd zmm9, zmm9, zmm14 vpxord zmm5, zmm5, zmm10 vpxord zmm6, zmm6, zmm11 vpxord zmm7, zmm7, zmm8 vpxord zmm4, zmm4, zmm9 vprord zmm5, zmm5, 7 vprord zmm6, zmm6, 7 vprord zmm7, zmm7, 7 vprord zmm4, zmm4, 7 vpaddd zmm0, zmm0, zmm19 vpaddd zmm1, zmm1, zmm26 vpaddd zmm2, zmm2, zmm29 vpaddd zmm3, zmm3, zmm23 vpaddd zmm0, zmm0, zmm4 vpaddd zmm1, zmm1, zmm5 vpaddd zmm2, zmm2, zmm6 vpaddd zmm3, zmm3, zmm7 vpxord zmm12, zmm12, zmm0 vpxord zmm13, zmm13, zmm1 vpxord zmm14, zmm14, zmm2 vpxord zmm15, zmm15, zmm3 vprord zmm12, zmm12, 16 vprord zmm13, zmm13, 16 vprord zmm14, zmm14, 16 vprord zmm15, zmm15, 16 vpaddd zmm8, zmm8, zmm12 vpaddd zmm9, zmm9, zmm13 vpaddd zmm10, zmm10, zmm14 vpaddd zmm11, zmm11, zmm15 vpxord zmm4, zmm4, zmm8 vpxord zmm5, zmm5, zmm9 vpxord zmm6, zmm6, zmm10 vpxord zmm7, zmm7, zmm11 vprord zmm4, zmm4, 12 vprord zmm5, zmm5, 12 vprord zmm6, zmm6, 12 vprord zmm7, zmm7, 12 vpaddd zmm0, zmm0, zmm20 vpaddd zmm1, zmm1, zmm28 vpaddd zmm2, zmm2, zmm18 vpaddd zmm3, zmm3, zmm30 vpaddd zmm0, zmm0, zmm4 vpaddd zmm1, zmm1, zmm5 vpaddd zmm2, zmm2, zmm6 vpaddd zmm3, zmm3, zmm7 vpxord zmm12, zmm12, zmm0 vpxord zmm13, zmm13, zmm1 vpxord zmm14, zmm14, zmm2 vpxord zmm15, zmm15, zmm3 vprord zmm12, zmm12, 8 vprord zmm13, zmm13, 8 vprord zmm14, zmm14, 8 vprord zmm15, zmm15, 8 vpaddd zmm8, zmm8, zmm12 vpaddd zmm9, zmm9, zmm13 vpaddd zmm10, zmm10, zmm14 vpaddd zmm11, zmm11, zmm15 vpxord zmm4, zmm4, zmm8 vpxord zmm5, zmm5, zmm9 vpxord zmm6, zmm6, zmm10 vpxord zmm7, zmm7, zmm11 vprord zmm4, zmm4, 7 vprord zmm5, zmm5, 7 vprord zmm6, zmm6, 7 vprord zmm7, zmm7, 7 vpaddd zmm0, zmm0, zmm22 vpaddd zmm1, zmm1, zmm25 vpaddd zmm2, zmm2, zmm27 vpaddd zmm3, zmm3, zmm24 vpaddd zmm0, zmm0, zmm5 vpaddd zmm1, zmm1, zmm6 vpaddd zmm2, zmm2, zmm7 vpaddd zmm3, zmm3, zmm4 vpxord zmm15, zmm15, zmm0 vpxord zmm12, zmm12, zmm1 vpxord zmm13, zmm13, zmm2 vpxord zmm14, zmm14, zmm3 vprord zmm15, zmm15, 16 vprord zmm12, zmm12, 16 vprord zmm13, zmm13, 16 vprord zmm14, zmm14, 16 vpaddd zmm10, zmm10, zmm15 vpaddd zmm11, zmm11, zmm12 vpaddd zmm8, zmm8, zmm13 vpaddd zmm9, zmm9, zmm14 vpxord zmm5, zmm5, zmm10 vpxord zmm6, zmm6, zmm11 vpxord zmm7, zmm7, zmm8 vpxord zmm4, zmm4, zmm9 vprord zmm5, zmm5, 12 vprord zmm6, zmm6, 12 vprord zmm7, zmm7, 12 vprord zmm4, zmm4, 12 vpaddd zmm0, zmm0, zmm21 vpaddd zmm1, zmm1, zmm16 vpaddd zmm2, zmm2, zmm31 vpaddd zmm3, zmm3, zmm17 vpaddd zmm0, zmm0, zmm5 vpaddd zmm1, zmm1, zmm6 vpaddd zmm2, zmm2, zmm7 vpaddd zmm3, zmm3, zmm4 vpxord zmm15, zmm15, zmm0 vpxord zmm12, zmm12, zmm1 vpxord zmm13, zmm13, zmm2 vpxord zmm14, zmm14, zmm3 vprord zmm15, zmm15, 8 vprord zmm12, zmm12, 8 vprord zmm13, zmm13, 8 vprord zmm14, zmm14, 8 vpaddd zmm10, zmm10, zmm15 vpaddd zmm11, zmm11, zmm12 vpaddd zmm8, zmm8, zmm13 vpaddd zmm9, zmm9, zmm14 vpxord zmm5, zmm5, zmm10 vpxord zmm6, zmm6, zmm11 vpxord zmm7, zmm7, zmm8 vpxord zmm4, zmm4, zmm9 vprord zmm5, zmm5, 7 vprord zmm6, zmm6, 7 vprord zmm7, zmm7, 7 vprord zmm4, zmm4, 7 vpaddd zmm0, zmm0, zmm26 vpaddd zmm1, zmm1, zmm28 vpaddd zmm2, zmm2, zmm30 vpaddd zmm3, zmm3, zmm29 vpaddd zmm0, zmm0, zmm4 vpaddd zmm1, zmm1, zmm5 vpaddd zmm2, zmm2, zmm6 vpaddd zmm3, zmm3, zmm7 vpxord zmm12, zmm12, zmm0 vpxord zmm13, zmm13, zmm1 vpxord zmm14, zmm14, zmm2 vpxord zmm15, zmm15, zmm3 vprord zmm12, zmm12, 16 vprord zmm13, zmm13, 16 vprord zmm14, zmm14, 16 vprord zmm15, zmm15, 16 vpaddd zmm8, zmm8, zmm12 vpaddd zmm9, zmm9, zmm13 vpaddd zmm10, zmm10, zmm14 vpaddd zmm11, zmm11, zmm15 vpxord zmm4, zmm4, zmm8 vpxord zmm5, zmm5, zmm9 vpxord zmm6, zmm6, zmm10 vpxord zmm7, zmm7, zmm11 vprord zmm4, zmm4, 12 vprord zmm5, zmm5, 12 vprord zmm6, zmm6, 12 vprord zmm7, zmm7, 12 vpaddd zmm0, zmm0, zmm23 vpaddd zmm1, zmm1, zmm25 vpaddd zmm2, zmm2, zmm19 vpaddd zmm3, zmm3, zmm31 vpaddd zmm0, zmm0, zmm4 vpaddd zmm1, zmm1, zmm5 vpaddd zmm2, zmm2, zmm6 vpaddd zmm3, zmm3, zmm7 vpxord zmm12, zmm12, zmm0 vpxord zmm13, zmm13, zmm1 vpxord zmm14, zmm14, zmm2 vpxord zmm15, zmm15, zmm3 vprord zmm12, zmm12, 8 vprord zmm13, zmm13, 8 vprord zmm14, zmm14, 8 vprord zmm15, zmm15, 8 vpaddd zmm8, zmm8, zmm12 vpaddd zmm9, zmm9, zmm13 vpaddd zmm10, zmm10, zmm14 vpaddd zmm11, zmm11, zmm15 vpxord zmm4, zmm4, zmm8 vpxord zmm5, zmm5, zmm9 vpxord zmm6, zmm6, zmm10 vpxord zmm7, zmm7, zmm11 vprord zmm4, zmm4, 7 vprord zmm5, zmm5, 7 vprord zmm6, zmm6, 7 vprord zmm7, zmm7, 7 vpaddd zmm0, zmm0, zmm20 vpaddd zmm1, zmm1, zmm27 vpaddd zmm2, zmm2, zmm21 vpaddd zmm3, zmm3, zmm17 vpaddd zmm0, zmm0, zmm5 vpaddd zmm1, zmm1, zmm6 vpaddd zmm2, zmm2, zmm7 vpaddd zmm3, zmm3, zmm4 vpxord zmm15, zmm15, zmm0 vpxord zmm12, zmm12, zmm1 vpxord zmm13, zmm13, zmm2 vpxord zmm14, zmm14, zmm3 vprord zmm15, zmm15, 16 vprord zmm12, zmm12, 16 vprord zmm13, zmm13, 16 vprord zmm14, zmm14, 16 vpaddd zmm10, zmm10, zmm15 vpaddd zmm11, zmm11, zmm12 vpaddd zmm8, zmm8, zmm13 vpaddd zmm9, zmm9, zmm14 vpxord zmm5, zmm5, zmm10 vpxord zmm6, zmm6, zmm11 vpxord zmm7, zmm7, zmm8 vpxord zmm4, zmm4, zmm9 vprord zmm5, zmm5, 12 vprord zmm6, zmm6, 12 vprord zmm7, zmm7, 12 vprord zmm4, zmm4, 12 vpaddd zmm0, zmm0, zmm16 vpaddd zmm1, zmm1, zmm18 vpaddd zmm2, zmm2, zmm24 vpaddd zmm3, zmm3, zmm22 vpaddd zmm0, zmm0, zmm5 vpaddd zmm1, zmm1, zmm6 vpaddd zmm2, zmm2, zmm7 vpaddd zmm3, zmm3, zmm4 vpxord zmm15, zmm15, zmm0 vpxord zmm12, zmm12, zmm1 vpxord zmm13, zmm13, zmm2 vpxord zmm14, zmm14, zmm3 vprord zmm15, zmm15, 8 vprord zmm12, zmm12, 8 vprord zmm13, zmm13, 8 vprord zmm14, zmm14, 8 vpaddd zmm10, zmm10, zmm15 vpaddd zmm11, zmm11, zmm12 vpaddd zmm8, zmm8, zmm13 vpaddd zmm9, zmm9, zmm14 vpxord zmm5, zmm5, zmm10 vpxord zmm6, zmm6, zmm11 vpxord zmm7, zmm7, zmm8 vpxord zmm4, zmm4, zmm9 vprord zmm5, zmm5, 7 vprord zmm6, zmm6, 7 vprord zmm7, zmm7, 7 vprord zmm4, zmm4, 7 vpaddd zmm0, zmm0, zmm28 vpaddd zmm1, zmm1, zmm25 vpaddd zmm2, zmm2, zmm31 vpaddd zmm3, zmm3, zmm30 vpaddd zmm0, zmm0, zmm4 vpaddd zmm1, zmm1, zmm5 vpaddd zmm2, zmm2, zmm6 vpaddd zmm3, zmm3, zmm7 vpxord zmm12, zmm12, zmm0 vpxord zmm13, zmm13, zmm1 vpxord zmm14, zmm14, zmm2 vpxord zmm15, zmm15, zmm3 vprord zmm12, zmm12, 16 vprord zmm13, zmm13, 16 vprord zmm14, zmm14, 16 vprord zmm15, zmm15, 16 vpaddd zmm8, zmm8, zmm12 vpaddd zmm9, zmm9, zmm13 vpaddd zmm10, zmm10, zmm14 vpaddd zmm11, zmm11, zmm15 vpxord zmm4, zmm4, zmm8 vpxord zmm5, zmm5, zmm9 vpxord zmm6, zmm6, zmm10 vpxord zmm7, zmm7, zmm11 vprord zmm4, zmm4, 12 vprord zmm5, zmm5, 12 vprord zmm6, zmm6, 12 vprord zmm7, zmm7, 12 vpaddd zmm0, zmm0, zmm29 vpaddd zmm1, zmm1, zmm27 vpaddd zmm2, zmm2, zmm26 vpaddd zmm3, zmm3, zmm24 vpaddd zmm0, zmm0, zmm4 vpaddd zmm1, zmm1, zmm5 vpaddd zmm2, zmm2, zmm6 vpaddd zmm3, zmm3, zmm7 vpxord zmm12, zmm12, zmm0 vpxord zmm13, zmm13, zmm1 vpxord zmm14, zmm14, zmm2 vpxord zmm15, zmm15, zmm3 vprord zmm12, zmm12, 8 vprord zmm13, zmm13, 8 vprord zmm14, zmm14, 8 vprord zmm15, zmm15, 8 vpaddd zmm8, zmm8, zmm12 vpaddd zmm9, zmm9, zmm13 vpaddd zmm10, zmm10, zmm14 vpaddd zmm11, zmm11, zmm15 vpxord zmm4, zmm4, zmm8 vpxord zmm5, zmm5, zmm9 vpxord zmm6, zmm6, zmm10 vpxord zmm7, zmm7, zmm11 vprord zmm4, zmm4, 7 vprord zmm5, zmm5, 7 vprord zmm6, zmm6, 7 vprord zmm7, zmm7, 7 vpaddd zmm0, zmm0, zmm23 vpaddd zmm1, zmm1, zmm21 vpaddd zmm2, zmm2, zmm16 vpaddd zmm3, zmm3, zmm22 vpaddd zmm0, zmm0, zmm5 vpaddd zmm1, zmm1, zmm6 vpaddd zmm2, zmm2, zmm7 vpaddd zmm3, zmm3, zmm4 vpxord zmm15, zmm15, zmm0 vpxord zmm12, zmm12, zmm1 vpxord zmm13, zmm13, zmm2 vpxord zmm14, zmm14, zmm3 vprord zmm15, zmm15, 16 vprord zmm12, zmm12, 16 vprord zmm13, zmm13, 16 vprord zmm14, zmm14, 16 vpaddd zmm10, zmm10, zmm15 vpaddd zmm11, zmm11, zmm12 vpaddd zmm8, zmm8, zmm13 vpaddd zmm9, zmm9, zmm14 vpxord zmm5, zmm5, zmm10 vpxord zmm6, zmm6, zmm11 vpxord zmm7, zmm7, zmm8 vpxord zmm4, zmm4, zmm9 vprord zmm5, zmm5, 12 vprord zmm6, zmm6, 12 vprord zmm7, zmm7, 12 vprord zmm4, zmm4, 12 vpaddd zmm0, zmm0, zmm18 vpaddd zmm1, zmm1, zmm19 vpaddd zmm2, zmm2, zmm17 vpaddd zmm3, zmm3, zmm20 vpaddd zmm0, zmm0, zmm5 vpaddd zmm1, zmm1, zmm6 vpaddd zmm2, zmm2, zmm7 vpaddd zmm3, zmm3, zmm4 vpxord zmm15, zmm15, zmm0 vpxord zmm12, zmm12, zmm1 vpxord zmm13, zmm13, zmm2 vpxord zmm14, zmm14, zmm3 vprord zmm15, zmm15, 8 vprord zmm12, zmm12, 8 vprord zmm13, zmm13, 8 vprord zmm14, zmm14, 8 vpaddd zmm10, zmm10, zmm15 vpaddd zmm11, zmm11, zmm12 vpaddd zmm8, zmm8, zmm13 vpaddd zmm9, zmm9, zmm14 vpxord zmm5, zmm5, zmm10 vpxord zmm6, zmm6, zmm11 vpxord zmm7, zmm7, zmm8 vpxord zmm4, zmm4, zmm9 vprord zmm5, zmm5, 7 vprord zmm6, zmm6, 7 vprord zmm7, zmm7, 7 vprord zmm4, zmm4, 7 vpaddd zmm0, zmm0, zmm25 vpaddd zmm1, zmm1, zmm27 vpaddd zmm2, zmm2, zmm24 vpaddd zmm3, zmm3, zmm31 vpaddd zmm0, zmm0, zmm4 vpaddd zmm1, zmm1, zmm5 vpaddd zmm2, zmm2, zmm6 vpaddd zmm3, zmm3, zmm7 vpxord zmm12, zmm12, zmm0 vpxord zmm13, zmm13, zmm1 vpxord zmm14, zmm14, zmm2 vpxord zmm15, zmm15, zmm3 vprord zmm12, zmm12, 16 vprord zmm13, zmm13, 16 vprord zmm14, zmm14, 16 vprord zmm15, zmm15, 16 vpaddd zmm8, zmm8, zmm12 vpaddd zmm9, zmm9, zmm13 vpaddd zmm10, zmm10, zmm14 vpaddd zmm11, zmm11, zmm15 vpxord zmm4, zmm4, zmm8 vpxord zmm5, zmm5, zmm9 vpxord zmm6, zmm6, zmm10 vpxord zmm7, zmm7, zmm11 vprord zmm4, zmm4, 12 vprord zmm5, zmm5, 12 vprord zmm6, zmm6, 12 vprord zmm7, zmm7, 12 vpaddd zmm0, zmm0, zmm30 vpaddd zmm1, zmm1, zmm21 vpaddd zmm2, zmm2, zmm28 vpaddd zmm3, zmm3, zmm17 vpaddd zmm0, zmm0, zmm4 vpaddd zmm1, zmm1, zmm5 vpaddd zmm2, zmm2, zmm6 vpaddd zmm3, zmm3, zmm7 vpxord zmm12, zmm12, zmm0 vpxord zmm13, zmm13, zmm1 vpxord zmm14, zmm14, zmm2 vpxord zmm15, zmm15, zmm3 vprord zmm12, zmm12, 8 vprord zmm13, zmm13, 8 vprord zmm14, zmm14, 8 vprord zmm15, zmm15, 8 vpaddd zmm8, zmm8, zmm12 vpaddd zmm9, zmm9, zmm13 vpaddd zmm10, zmm10, zmm14 vpaddd zmm11, zmm11, zmm15 vpxord zmm4, zmm4, zmm8 vpxord zmm5, zmm5, zmm9 vpxord zmm6, zmm6, zmm10 vpxord zmm7, zmm7, zmm11 vprord zmm4, zmm4, 7 vprord zmm5, zmm5, 7 vprord zmm6, zmm6, 7 vprord zmm7, zmm7, 7 vpaddd zmm0, zmm0, zmm29 vpaddd zmm1, zmm1, zmm16 vpaddd zmm2, zmm2, zmm18 vpaddd zmm3, zmm3, zmm20 vpaddd zmm0, zmm0, zmm5 vpaddd zmm1, zmm1, zmm6 vpaddd zmm2, zmm2, zmm7 vpaddd zmm3, zmm3, zmm4 vpxord zmm15, zmm15, zmm0 vpxord zmm12, zmm12, zmm1 vpxord zmm13, zmm13, zmm2 vpxord zmm14, zmm14, zmm3 vprord zmm15, zmm15, 16 vprord zmm12, zmm12, 16 vprord zmm13, zmm13, 16 vprord zmm14, zmm14, 16 vpaddd zmm10, zmm10, zmm15 vpaddd zmm11, zmm11, zmm12 vpaddd zmm8, zmm8, zmm13 vpaddd zmm9, zmm9, zmm14 vpxord zmm5, zmm5, zmm10 vpxord zmm6, zmm6, zmm11 vpxord zmm7, zmm7, zmm8 vpxord zmm4, zmm4, zmm9 vprord zmm5, zmm5, 12 vprord zmm6, zmm6, 12 vprord zmm7, zmm7, 12 vprord zmm4, zmm4, 12 vpaddd zmm0, zmm0, zmm19 vpaddd zmm1, zmm1, zmm26 vpaddd zmm2, zmm2, zmm22 vpaddd zmm3, zmm3, zmm23 vpaddd zmm0, zmm0, zmm5 vpaddd zmm1, zmm1, zmm6 vpaddd zmm2, zmm2, zmm7 vpaddd zmm3, zmm3, zmm4 vpxord zmm15, zmm15, zmm0 vpxord zmm12, zmm12, zmm1 vpxord zmm13, zmm13, zmm2 vpxord zmm14, zmm14, zmm3 vprord zmm15, zmm15, 8 vprord zmm12, zmm12, 8 vprord zmm13, zmm13, 8 vprord zmm14, zmm14, 8 vpaddd zmm10, zmm10, zmm15 vpaddd zmm11, zmm11, zmm12 vpaddd zmm8, zmm8, zmm13 vpaddd zmm9, zmm9, zmm14 vpxord zmm5, zmm5, zmm10 vpxord zmm6, zmm6, zmm11 vpxord zmm7, zmm7, zmm8 vpxord zmm4, zmm4, zmm9 vprord zmm5, zmm5, 7 vprord zmm6, zmm6, 7 vprord zmm7, zmm7, 7 vprord zmm4, zmm4, 7 vpaddd zmm0, zmm0, zmm27 vpaddd zmm1, zmm1, zmm21 vpaddd zmm2, zmm2, zmm17 vpaddd zmm3, zmm3, zmm24 vpaddd zmm0, zmm0, zmm4 vpaddd zmm1, zmm1, zmm5 vpaddd zmm2, zmm2, zmm6 vpaddd zmm3, zmm3, zmm7 vpxord zmm12, zmm12, zmm0 vpxord zmm13, zmm13, zmm1 vpxord zmm14, zmm14, zmm2 vpxord zmm15, zmm15, zmm3 vprord zmm12, zmm12, 16 vprord zmm13, zmm13, 16 vprord zmm14, zmm14, 16 vprord zmm15, zmm15, 16 vpaddd zmm8, zmm8, zmm12 vpaddd zmm9, zmm9, zmm13 vpaddd zmm10, zmm10, zmm14 vpaddd zmm11, zmm11, zmm15 vpxord zmm4, zmm4, zmm8 vpxord zmm5, zmm5, zmm9 vpxord zmm6, zmm6, zmm10 vpxord zmm7, zmm7, zmm11 vprord zmm4, zmm4, 12 vprord zmm5, zmm5, 12 vprord zmm6, zmm6, 12 vprord zmm7, zmm7, 12 vpaddd zmm0, zmm0, zmm31 vpaddd zmm1, zmm1, zmm16 vpaddd zmm2, zmm2, zmm25 vpaddd zmm3, zmm3, zmm22 vpaddd zmm0, zmm0, zmm4 vpaddd zmm1, zmm1, zmm5 vpaddd zmm2, zmm2, zmm6 vpaddd zmm3, zmm3, zmm7 vpxord zmm12, zmm12, zmm0 vpxord zmm13, zmm13, zmm1 vpxord zmm14, zmm14, zmm2 vpxord zmm15, zmm15, zmm3 vprord zmm12, zmm12, 8 vprord zmm13, zmm13, 8 vprord zmm14, zmm14, 8 vprord zmm15, zmm15, 8 vpaddd zmm8, zmm8, zmm12 vpaddd zmm9, zmm9, zmm13 vpaddd zmm10, zmm10, zmm14 vpaddd zmm11, zmm11, zmm15 vpxord zmm4, zmm4, zmm8 vpxord zmm5, zmm5, zmm9 vpxord zmm6, zmm6, zmm10 vpxord zmm7, zmm7, zmm11 vprord zmm4, zmm4, 7 vprord zmm5, zmm5, 7 vprord zmm6, zmm6, 7 vprord zmm7, zmm7, 7 vpaddd zmm0, zmm0, zmm30 vpaddd zmm1, zmm1, zmm18 vpaddd zmm2, zmm2, zmm19 vpaddd zmm3, zmm3, zmm23 vpaddd zmm0, zmm0, zmm5 vpaddd zmm1, zmm1, zmm6 vpaddd zmm2, zmm2, zmm7 vpaddd zmm3, zmm3, zmm4 vpxord zmm15, zmm15, zmm0 vpxord zmm12, zmm12, zmm1 vpxord zmm13, zmm13, zmm2 vpxord zmm14, zmm14, zmm3 vprord zmm15, zmm15, 16 vprord zmm12, zmm12, 16 vprord zmm13, zmm13, 16 vprord zmm14, zmm14, 16 vpaddd zmm10, zmm10, zmm15 vpaddd zmm11, zmm11, zmm12 vpaddd zmm8, zmm8, zmm13 vpaddd zmm9, zmm9, zmm14 vpxord zmm5, zmm5, zmm10 vpxord zmm6, zmm6, zmm11 vpxord zmm7, zmm7, zmm8 vpxord zmm4, zmm4, zmm9 vprord zmm5, zmm5, 12 vprord zmm6, zmm6, 12 vprord zmm7, zmm7, 12 vprord zmm4, zmm4, 12 vpaddd zmm0, zmm0, zmm26 vpaddd zmm1, zmm1, zmm28 vpaddd zmm2, zmm2, zmm20 vpaddd zmm3, zmm3, zmm29 vpaddd zmm0, zmm0, zmm5 vpaddd zmm1, zmm1, zmm6 vpaddd zmm2, zmm2, zmm7 vpaddd zmm3, zmm3, zmm4 vpxord zmm15, zmm15, zmm0 vpxord zmm12, zmm12, zmm1 vpxord zmm13, zmm13, zmm2 vpxord zmm14, zmm14, zmm3 vprord zmm15, zmm15, 8 vprord zmm12, zmm12, 8 vprord zmm13, zmm13, 8 vprord zmm14, zmm14, 8 vpaddd zmm10, zmm10, zmm15 vpaddd zmm11, zmm11, zmm12 vpaddd zmm8, zmm8, zmm13 vpaddd zmm9, zmm9, zmm14 vpxord zmm5, zmm5, zmm10 vpxord zmm6, zmm6, zmm11 vpxord zmm7, zmm7, zmm8 vpxord zmm4, zmm4, zmm9 vprord zmm5, zmm5, 7 vprord zmm6, zmm6, 7 vprord zmm7, zmm7, 7 vprord zmm4, zmm4, 7 vpxord zmm0, zmm0, zmm8 vpxord zmm1, zmm1, zmm9 vpxord zmm2, zmm2, zmm10 vpxord zmm3, zmm3, zmm11 vpxord zmm4, zmm4, zmm12 vpxord zmm5, zmm5, zmm13 vpxord zmm6, zmm6, zmm14 vpxord zmm7, zmm7, zmm15 movzx eax, byte ptr [rbp+0x38] jne 9b mov rbx, qword ptr [rbp+0x50] vpunpckldq zmm16, zmm0, zmm1 vpunpckhdq zmm17, zmm0, zmm1 vpunpckldq zmm18, zmm2, zmm3 vpunpckhdq zmm19, zmm2, zmm3 vpunpckldq zmm20, zmm4, zmm5 vpunpckhdq zmm21, zmm4, zmm5 vpunpckldq zmm22, zmm6, zmm7 vpunpckhdq zmm23, zmm6, zmm7 vpunpcklqdq zmm0, zmm16, zmm18 vpunpckhqdq zmm1, zmm16, zmm18 vpunpcklqdq zmm2, zmm17, zmm19 vpunpckhqdq zmm3, zmm17, zmm19 vpunpcklqdq zmm4, zmm20, zmm22 vpunpckhqdq zmm5, zmm20, zmm22 vpunpcklqdq zmm6, zmm21, zmm23 vpunpckhqdq zmm7, zmm21, zmm23 vshufi32x4 zmm16, zmm0, zmm4, 0x88 vshufi32x4 zmm17, zmm1, zmm5, 0x88 vshufi32x4 zmm18, zmm2, zmm6, 0x88 vshufi32x4 zmm19, zmm3, zmm7, 0x88 vshufi32x4 zmm20, zmm0, zmm4, 0xDD vshufi32x4 zmm21, zmm1, zmm5, 0xDD vshufi32x4 zmm22, zmm2, zmm6, 0xDD vshufi32x4 zmm23, zmm3, zmm7, 0xDD vshufi32x4 zmm0, zmm16, zmm17, 0x88 vshufi32x4 zmm1, zmm18, zmm19, 0x88 vshufi32x4 zmm2, zmm20, zmm21, 0x88 vshufi32x4 zmm3, zmm22, zmm23, 0x88 vshufi32x4 zmm4, zmm16, zmm17, 0xDD vshufi32x4 zmm5, zmm18, zmm19, 0xDD vshufi32x4 zmm6, zmm20, zmm21, 0xDD vshufi32x4 zmm7, zmm22, zmm23, 0xDD vmovdqu32 zmmword ptr [rbx], zmm0 vmovdqu32 zmmword ptr [rbx+0x1*0x40], zmm1 vmovdqu32 zmmword ptr [rbx+0x2*0x40], zmm2 vmovdqu32 zmmword ptr [rbx+0x3*0x40], zmm3 vmovdqu32 zmmword ptr [rbx+0x4*0x40], zmm4 vmovdqu32 zmmword ptr [rbx+0x5*0x40], zmm5 vmovdqu32 zmmword ptr [rbx+0x6*0x40], zmm6 vmovdqu32 zmmword ptr [rbx+0x7*0x40], zmm7 vmovdqa32 zmm0, zmmword ptr [rsp] vmovdqa32 zmm1, zmmword ptr [rsp+0x1*0x40] vmovdqa32 zmm2, zmm0 vpaddd zmm2{k1}, zmm0, dword ptr [ADD16+rip] {1to16} vpcmpltud k2, zmm2, zmm0 vpaddd zmm1 {k2}, zmm1, dword ptr [ADD1+rip] {1to16} vmovdqa32 zmmword ptr [rsp], zmm2 vmovdqa32 zmmword ptr [rsp+0x1*0x40], zmm1 add rdi, 128 add rbx, 512 mov qword ptr [rbp+0x50], rbx sub rsi, 16 cmp rsi, 16 jnc 2b test rsi, rsi jnz 3f 4: vzeroupper mov rsp, rbp pop rbp pop rbx pop r12 pop r13 pop r14 pop r15 ret .p2align 6 3: test esi, 0x8 je 3f vpbroadcastd ymm0, dword ptr [rcx] vpbroadcastd ymm1, dword ptr [rcx+0x4] vpbroadcastd ymm2, dword ptr [rcx+0x8] vpbroadcastd ymm3, dword ptr [rcx+0xC] vpbroadcastd ymm4, dword ptr [rcx+0x10] vpbroadcastd ymm5, dword ptr [rcx+0x14] vpbroadcastd ymm6, dword ptr [rcx+0x18] vpbroadcastd ymm7, dword ptr [rcx+0x1C] mov r8, qword ptr [rdi] mov r9, qword ptr [rdi+0x8] mov r10, qword ptr [rdi+0x10] mov r11, qword ptr [rdi+0x18] mov r12, qword ptr [rdi+0x20] mov r13, qword ptr [rdi+0x28] mov r14, qword ptr [rdi+0x30] mov r15, qword ptr [rdi+0x38] movzx eax, byte ptr [rbp+0x38] movzx ebx, byte ptr [rbp+0x40] or eax, ebx xor edx, edx 2: movzx ebx, byte ptr [rbp+0x48] or ebx, eax add rdx, 64 cmp rdx, qword ptr [rsp+0x80] cmove eax, ebx mov dword ptr [rsp+0x88], eax vmovups xmm8, xmmword ptr [r8+rdx-0x40] vinsertf128 ymm8, ymm8, xmmword ptr [r12+rdx-0x40], 0x01 vmovups xmm9, xmmword ptr [r9+rdx-0x40] vinsertf128 ymm9, ymm9, xmmword ptr [r13+rdx-0x40], 0x01 vunpcklpd ymm12, ymm8, ymm9 vunpckhpd ymm13, ymm8, ymm9 vmovups xmm10, xmmword ptr [r10+rdx-0x40] vinsertf128 ymm10, ymm10, xmmword ptr [r14+rdx-0x40], 0x01 vmovups xmm11, xmmword ptr [r11+rdx-0x40] vinsertf128 ymm11, ymm11, xmmword ptr [r15+rdx-0x40], 0x01 vunpcklpd ymm14, ymm10, ymm11 vunpckhpd ymm15, ymm10, ymm11 vshufps ymm16, ymm12, ymm14, 136 vshufps ymm17, ymm12, ymm14, 221 vshufps ymm18, ymm13, ymm15, 136 vshufps ymm19, ymm13, ymm15, 221 vmovups xmm8, xmmword ptr [r8+rdx-0x30] vinsertf128 ymm8, ymm8, xmmword ptr [r12+rdx-0x30], 0x01 vmovups xmm9, xmmword ptr [r9+rdx-0x30] vinsertf128 ymm9, ymm9, xmmword ptr [r13+rdx-0x30], 0x01 vunpcklpd ymm12, ymm8, ymm9 vunpckhpd ymm13, ymm8, ymm9 vmovups xmm10, xmmword ptr [r10+rdx-0x30] vinsertf128 ymm10, ymm10, xmmword ptr [r14+rdx-0x30], 0x01 vmovups xmm11, xmmword ptr [r11+rdx-0x30] vinsertf128 ymm11, ymm11, xmmword ptr [r15+rdx-0x30], 0x01 vunpcklpd ymm14, ymm10, ymm11 vunpckhpd ymm15, ymm10, ymm11 vshufps ymm20, ymm12, ymm14, 136 vshufps ymm21, ymm12, ymm14, 221 vshufps ymm22, ymm13, ymm15, 136 vshufps ymm23, ymm13, ymm15, 221 vmovups xmm8, xmmword ptr [r8+rdx-0x20] vinsertf128 ymm8, ymm8, xmmword ptr [r12+rdx-0x20], 0x01 vmovups xmm9, xmmword ptr [r9+rdx-0x20] vinsertf128 ymm9, ymm9, xmmword ptr [r13+rdx-0x20], 0x01 vunpcklpd ymm12, ymm8, ymm9 vunpckhpd ymm13, ymm8, ymm9 vmovups xmm10, xmmword ptr [r10+rdx-0x20] vinsertf128 ymm10, ymm10, xmmword ptr [r14+rdx-0x20], 0x01 vmovups xmm11, xmmword ptr [r11+rdx-0x20] vinsertf128 ymm11, ymm11, xmmword ptr [r15+rdx-0x20], 0x01 vunpcklpd ymm14, ymm10, ymm11 vunpckhpd ymm15, ymm10, ymm11 vshufps ymm24, ymm12, ymm14, 136 vshufps ymm25, ymm12, ymm14, 221 vshufps ymm26, ymm13, ymm15, 136 vshufps ymm27, ymm13, ymm15, 221 vmovups xmm8, xmmword ptr [r8+rdx-0x10] vinsertf128 ymm8, ymm8, xmmword ptr [r12+rdx-0x10], 0x01 vmovups xmm9, xmmword ptr [r9+rdx-0x10] vinsertf128 ymm9, ymm9, xmmword ptr [r13+rdx-0x10], 0x01 vunpcklpd ymm12, ymm8, ymm9 vunpckhpd ymm13, ymm8, ymm9 vmovups xmm10, xmmword ptr [r10+rdx-0x10] vinsertf128 ymm10, ymm10, xmmword ptr [r14+rdx-0x10], 0x01 vmovups xmm11, xmmword ptr [r11+rdx-0x10] vinsertf128 ymm11, ymm11, xmmword ptr [r15+rdx-0x10], 0x01 vunpcklpd ymm14, ymm10, ymm11 vunpckhpd ymm15, ymm10, ymm11 vshufps ymm28, ymm12, ymm14, 136 vshufps ymm29, ymm12, ymm14, 221 vshufps ymm30, ymm13, ymm15, 136 vshufps ymm31, ymm13, ymm15, 221 vpbroadcastd ymm8, dword ptr [BLAKE3_IV_0+rip] vpbroadcastd ymm9, dword ptr [BLAKE3_IV_1+rip] vpbroadcastd ymm10, dword ptr [BLAKE3_IV_2+rip] vpbroadcastd ymm11, dword ptr [BLAKE3_IV_3+rip] vmovdqa ymm12, ymmword ptr [rsp] vmovdqa ymm13, ymmword ptr [rsp+0x40] vpbroadcastd ymm14, dword ptr [BLAKE3_BLOCK_LEN+rip] vpbroadcastd ymm15, dword ptr [rsp+0x88] vpaddd ymm0, ymm0, ymm16 vpaddd ymm1, ymm1, ymm18 vpaddd ymm2, ymm2, ymm20 vpaddd ymm3, ymm3, ymm22 vpaddd ymm0, ymm0, ymm4 vpaddd ymm1, ymm1, ymm5 vpaddd ymm2, ymm2, ymm6 vpaddd ymm3, ymm3, ymm7 vpxord ymm12, ymm12, ymm0 vpxord ymm13, ymm13, ymm1 vpxord ymm14, ymm14, ymm2 vpxord ymm15, ymm15, ymm3 vprord ymm12, ymm12, 16 vprord ymm13, ymm13, 16 vprord ymm14, ymm14, 16 vprord ymm15, ymm15, 16 vpaddd ymm8, ymm8, ymm12 vpaddd ymm9, ymm9, ymm13 vpaddd ymm10, ymm10, ymm14 vpaddd ymm11, ymm11, ymm15 vpxord ymm4, ymm4, ymm8 vpxord ymm5, ymm5, ymm9 vpxord ymm6, ymm6, ymm10 vpxord ymm7, ymm7, ymm11 vprord ymm4, ymm4, 12 vprord ymm5, ymm5, 12 vprord ymm6, ymm6, 12 vprord ymm7, ymm7, 12 vpaddd ymm0, ymm0, ymm17 vpaddd ymm1, ymm1, ymm19 vpaddd ymm2, ymm2, ymm21 vpaddd ymm3, ymm3, ymm23 vpaddd ymm0, ymm0, ymm4 vpaddd ymm1, ymm1, ymm5 vpaddd ymm2, ymm2, ymm6 vpaddd ymm3, ymm3, ymm7 vpxord ymm12, ymm12, ymm0 vpxord ymm13, ymm13, ymm1 vpxord ymm14, ymm14, ymm2 vpxord ymm15, ymm15, ymm3 vprord ymm12, ymm12, 8 vprord ymm13, ymm13, 8 vprord ymm14, ymm14, 8 vprord ymm15, ymm15, 8 vpaddd ymm8, ymm8, ymm12 vpaddd ymm9, ymm9, ymm13 vpaddd ymm10, ymm10, ymm14 vpaddd ymm11, ymm11, ymm15 vpxord ymm4, ymm4, ymm8 vpxord ymm5, ymm5, ymm9 vpxord ymm6, ymm6, ymm10 vpxord ymm7, ymm7, ymm11 vprord ymm4, ymm4, 7 vprord ymm5, ymm5, 7 vprord ymm6, ymm6, 7 vprord ymm7, ymm7, 7 vpaddd ymm0, ymm0, ymm24 vpaddd ymm1, ymm1, ymm26 vpaddd ymm2, ymm2, ymm28 vpaddd ymm3, ymm3, ymm30 vpaddd ymm0, ymm0, ymm5 vpaddd ymm1, ymm1, ymm6 vpaddd ymm2, ymm2, ymm7 vpaddd ymm3, ymm3, ymm4 vpxord ymm15, ymm15, ymm0 vpxord ymm12, ymm12, ymm1 vpxord ymm13, ymm13, ymm2 vpxord ymm14, ymm14, ymm3 vprord ymm15, ymm15, 16 vprord ymm12, ymm12, 16 vprord ymm13, ymm13, 16 vprord ymm14, ymm14, 16 vpaddd ymm10, ymm10, ymm15 vpaddd ymm11, ymm11, ymm12 vpaddd ymm8, ymm8, ymm13 vpaddd ymm9, ymm9, ymm14 vpxord ymm5, ymm5, ymm10 vpxord ymm6, ymm6, ymm11 vpxord ymm7, ymm7, ymm8 vpxord ymm4, ymm4, ymm9 vprord ymm5, ymm5, 12 vprord ymm6, ymm6, 12 vprord ymm7, ymm7, 12 vprord ymm4, ymm4, 12 vpaddd ymm0, ymm0, ymm25 vpaddd ymm1, ymm1, ymm27 vpaddd ymm2, ymm2, ymm29 vpaddd ymm3, ymm3, ymm31 vpaddd ymm0, ymm0, ymm5 vpaddd ymm1, ymm1, ymm6 vpaddd ymm2, ymm2, ymm7 vpaddd ymm3, ymm3, ymm4 vpxord ymm15, ymm15, ymm0 vpxord ymm12, ymm12, ymm1 vpxord ymm13, ymm13, ymm2 vpxord ymm14, ymm14, ymm3 vprord ymm15, ymm15, 8 vprord ymm12, ymm12, 8 vprord ymm13, ymm13, 8 vprord ymm14, ymm14, 8 vpaddd ymm10, ymm10, ymm15 vpaddd ymm11, ymm11, ymm12 vpaddd ymm8, ymm8, ymm13 vpaddd ymm9, ymm9, ymm14 vpxord ymm5, ymm5, ymm10 vpxord ymm6, ymm6, ymm11 vpxord ymm7, ymm7, ymm8 vpxord ymm4, ymm4, ymm9 vprord ymm5, ymm5, 7 vprord ymm6, ymm6, 7 vprord ymm7, ymm7, 7 vprord ymm4, ymm4, 7 vpaddd ymm0, ymm0, ymm18 vpaddd ymm1, ymm1, ymm19 vpaddd ymm2, ymm2, ymm23 vpaddd ymm3, ymm3, ymm20 vpaddd ymm0, ymm0, ymm4 vpaddd ymm1, ymm1, ymm5 vpaddd ymm2, ymm2, ymm6 vpaddd ymm3, ymm3, ymm7 vpxord ymm12, ymm12, ymm0 vpxord ymm13, ymm13, ymm1 vpxord ymm14, ymm14, ymm2 vpxord ymm15, ymm15, ymm3 vprord ymm12, ymm12, 16 vprord ymm13, ymm13, 16 vprord ymm14, ymm14, 16 vprord ymm15, ymm15, 16 vpaddd ymm8, ymm8, ymm12 vpaddd ymm9, ymm9, ymm13 vpaddd ymm10, ymm10, ymm14 vpaddd ymm11, ymm11, ymm15 vpxord ymm4, ymm4, ymm8 vpxord ymm5, ymm5, ymm9 vpxord ymm6, ymm6, ymm10 vpxord ymm7, ymm7, ymm11 vprord ymm4, ymm4, 12 vprord ymm5, ymm5, 12 vprord ymm6, ymm6, 12 vprord ymm7, ymm7, 12 vpaddd ymm0, ymm0, ymm22 vpaddd ymm1, ymm1, ymm26 vpaddd ymm2, ymm2, ymm16 vpaddd ymm3, ymm3, ymm29 vpaddd ymm0, ymm0, ymm4 vpaddd ymm1, ymm1, ymm5 vpaddd ymm2, ymm2, ymm6 vpaddd ymm3, ymm3, ymm7 vpxord ymm12, ymm12, ymm0 vpxord ymm13, ymm13, ymm1 vpxord ymm14, ymm14, ymm2 vpxord ymm15, ymm15, ymm3 vprord ymm12, ymm12, 8 vprord ymm13, ymm13, 8 vprord ymm14, ymm14, 8 vprord ymm15, ymm15, 8 vpaddd ymm8, ymm8, ymm12 vpaddd ymm9, ymm9, ymm13 vpaddd ymm10, ymm10, ymm14 vpaddd ymm11, ymm11, ymm15 vpxord ymm4, ymm4, ymm8 vpxord ymm5, ymm5, ymm9 vpxord ymm6, ymm6, ymm10 vpxord ymm7, ymm7, ymm11 vprord ymm4, ymm4, 7 vprord ymm5, ymm5, 7 vprord ymm6, ymm6, 7 vprord ymm7, ymm7, 7 vpaddd ymm0, ymm0, ymm17 vpaddd ymm1, ymm1, ymm28 vpaddd ymm2, ymm2, ymm25 vpaddd ymm3, ymm3, ymm31 vpaddd ymm0, ymm0, ymm5 vpaddd ymm1, ymm1, ymm6 vpaddd ymm2, ymm2, ymm7 vpaddd ymm3, ymm3, ymm4 vpxord ymm15, ymm15, ymm0 vpxord ymm12, ymm12, ymm1 vpxord ymm13, ymm13, ymm2 vpxord ymm14, ymm14, ymm3 vprord ymm15, ymm15, 16 vprord ymm12, ymm12, 16 vprord ymm13, ymm13, 16 vprord ymm14, ymm14, 16 vpaddd ymm10, ymm10, ymm15 vpaddd ymm11, ymm11, ymm12 vpaddd ymm8, ymm8, ymm13 vpaddd ymm9, ymm9, ymm14 vpxord ymm5, ymm5, ymm10 vpxord ymm6, ymm6, ymm11 vpxord ymm7, ymm7, ymm8 vpxord ymm4, ymm4, ymm9 vprord ymm5, ymm5, 12 vprord ymm6, ymm6, 12 vprord ymm7, ymm7, 12 vprord ymm4, ymm4, 12 vpaddd ymm0, ymm0, ymm27 vpaddd ymm1, ymm1, ymm21 vpaddd ymm2, ymm2, ymm30 vpaddd ymm3, ymm3, ymm24 vpaddd ymm0, ymm0, ymm5 vpaddd ymm1, ymm1, ymm6 vpaddd ymm2, ymm2, ymm7 vpaddd ymm3, ymm3, ymm4 vpxord ymm15, ymm15, ymm0 vpxord ymm12, ymm12, ymm1 vpxord ymm13, ymm13, ymm2 vpxord ymm14, ymm14, ymm3 vprord ymm15, ymm15, 8 vprord ymm12, ymm12, 8 vprord ymm13, ymm13, 8 vprord ymm14, ymm14, 8 vpaddd ymm10, ymm10, ymm15 vpaddd ymm11, ymm11, ymm12 vpaddd ymm8, ymm8, ymm13 vpaddd ymm9, ymm9, ymm14 vpxord ymm5, ymm5, ymm10 vpxord ymm6, ymm6, ymm11 vpxord ymm7, ymm7, ymm8 vpxord ymm4, ymm4, ymm9 vprord ymm5, ymm5, 7 vprord ymm6, ymm6, 7 vprord ymm7, ymm7, 7 vprord ymm4, ymm4, 7 vpaddd ymm0, ymm0, ymm19 vpaddd ymm1, ymm1, ymm26 vpaddd ymm2, ymm2, ymm29 vpaddd ymm3, ymm3, ymm23 vpaddd ymm0, ymm0, ymm4 vpaddd ymm1, ymm1, ymm5 vpaddd ymm2, ymm2, ymm6 vpaddd ymm3, ymm3, ymm7 vpxord ymm12, ymm12, ymm0 vpxord ymm13, ymm13, ymm1 vpxord ymm14, ymm14, ymm2 vpxord ymm15, ymm15, ymm3 vprord ymm12, ymm12, 16 vprord ymm13, ymm13, 16 vprord ymm14, ymm14, 16 vprord ymm15, ymm15, 16 vpaddd ymm8, ymm8, ymm12 vpaddd ymm9, ymm9, ymm13 vpaddd ymm10, ymm10, ymm14 vpaddd ymm11, ymm11, ymm15 vpxord ymm4, ymm4, ymm8 vpxord ymm5, ymm5, ymm9 vpxord ymm6, ymm6, ymm10 vpxord ymm7, ymm7, ymm11 vprord ymm4, ymm4, 12 vprord ymm5, ymm5, 12 vprord ymm6, ymm6, 12 vprord ymm7, ymm7, 12 vpaddd ymm0, ymm0, ymm20 vpaddd ymm1, ymm1, ymm28 vpaddd ymm2, ymm2, ymm18 vpaddd ymm3, ymm3, ymm30 vpaddd ymm0, ymm0, ymm4 vpaddd ymm1, ymm1, ymm5 vpaddd ymm2, ymm2, ymm6 vpaddd ymm3, ymm3, ymm7 vpxord ymm12, ymm12, ymm0 vpxord ymm13, ymm13, ymm1 vpxord ymm14, ymm14, ymm2 vpxord ymm15, ymm15, ymm3 vprord ymm12, ymm12, 8 vprord ymm13, ymm13, 8 vprord ymm14, ymm14, 8 vprord ymm15, ymm15, 8 vpaddd ymm8, ymm8, ymm12 vpaddd ymm9, ymm9, ymm13 vpaddd ymm10, ymm10, ymm14 vpaddd ymm11, ymm11, ymm15 vpxord ymm4, ymm4, ymm8 vpxord ymm5, ymm5, ymm9 vpxord ymm6, ymm6, ymm10 vpxord ymm7, ymm7, ymm11 vprord ymm4, ymm4, 7 vprord ymm5, ymm5, 7 vprord ymm6, ymm6, 7 vprord ymm7, ymm7, 7 vpaddd ymm0, ymm0, ymm22 vpaddd ymm1, ymm1, ymm25 vpaddd ymm2, ymm2, ymm27 vpaddd ymm3, ymm3, ymm24 vpaddd ymm0, ymm0, ymm5 vpaddd ymm1, ymm1, ymm6 vpaddd ymm2, ymm2, ymm7 vpaddd ymm3, ymm3, ymm4 vpxord ymm15, ymm15, ymm0 vpxord ymm12, ymm12, ymm1 vpxord ymm13, ymm13, ymm2 vpxord ymm14, ymm14, ymm3 vprord ymm15, ymm15, 16 vprord ymm12, ymm12, 16 vprord ymm13, ymm13, 16 vprord ymm14, ymm14, 16 vpaddd ymm10, ymm10, ymm15 vpaddd ymm11, ymm11, ymm12 vpaddd ymm8, ymm8, ymm13 vpaddd ymm9, ymm9, ymm14 vpxord ymm5, ymm5, ymm10 vpxord ymm6, ymm6, ymm11 vpxord ymm7, ymm7, ymm8 vpxord ymm4, ymm4, ymm9 vprord ymm5, ymm5, 12 vprord ymm6, ymm6, 12 vprord ymm7, ymm7, 12 vprord ymm4, ymm4, 12 vpaddd ymm0, ymm0, ymm21 vpaddd ymm1, ymm1, ymm16 vpaddd ymm2, ymm2, ymm31 vpaddd ymm3, ymm3, ymm17 vpaddd ymm0, ymm0, ymm5 vpaddd ymm1, ymm1, ymm6 vpaddd ymm2, ymm2, ymm7 vpaddd ymm3, ymm3, ymm4 vpxord ymm15, ymm15, ymm0 vpxord ymm12, ymm12, ymm1 vpxord ymm13, ymm13, ymm2 vpxord ymm14, ymm14, ymm3 vprord ymm15, ymm15, 8 vprord ymm12, ymm12, 8 vprord ymm13, ymm13, 8 vprord ymm14, ymm14, 8 vpaddd ymm10, ymm10, ymm15 vpaddd ymm11, ymm11, ymm12 vpaddd ymm8, ymm8, ymm13 vpaddd ymm9, ymm9, ymm14 vpxord ymm5, ymm5, ymm10 vpxord ymm6, ymm6, ymm11 vpxord ymm7, ymm7, ymm8 vpxord ymm4, ymm4, ymm9 vprord ymm5, ymm5, 7 vprord ymm6, ymm6, 7 vprord ymm7, ymm7, 7 vprord ymm4, ymm4, 7 vpaddd ymm0, ymm0, ymm26 vpaddd ymm1, ymm1, ymm28 vpaddd ymm2, ymm2, ymm30 vpaddd ymm3, ymm3, ymm29 vpaddd ymm0, ymm0, ymm4 vpaddd ymm1, ymm1, ymm5 vpaddd ymm2, ymm2, ymm6 vpaddd ymm3, ymm3, ymm7 vpxord ymm12, ymm12, ymm0 vpxord ymm13, ymm13, ymm1 vpxord ymm14, ymm14, ymm2 vpxord ymm15, ymm15, ymm3 vprord ymm12, ymm12, 16 vprord ymm13, ymm13, 16 vprord ymm14, ymm14, 16 vprord ymm15, ymm15, 16 vpaddd ymm8, ymm8, ymm12 vpaddd ymm9, ymm9, ymm13 vpaddd ymm10, ymm10, ymm14 vpaddd ymm11, ymm11, ymm15 vpxord ymm4, ymm4, ymm8 vpxord ymm5, ymm5, ymm9 vpxord ymm6, ymm6, ymm10 vpxord ymm7, ymm7, ymm11 vprord ymm4, ymm4, 12 vprord ymm5, ymm5, 12 vprord ymm6, ymm6, 12 vprord ymm7, ymm7, 12 vpaddd ymm0, ymm0, ymm23 vpaddd ymm1, ymm1, ymm25 vpaddd ymm2, ymm2, ymm19 vpaddd ymm3, ymm3, ymm31 vpaddd ymm0, ymm0, ymm4 vpaddd ymm1, ymm1, ymm5 vpaddd ymm2, ymm2, ymm6 vpaddd ymm3, ymm3, ymm7 vpxord ymm12, ymm12, ymm0 vpxord ymm13, ymm13, ymm1 vpxord ymm14, ymm14, ymm2 vpxord ymm15, ymm15, ymm3 vprord ymm12, ymm12, 8 vprord ymm13, ymm13, 8 vprord ymm14, ymm14, 8 vprord ymm15, ymm15, 8 vpaddd ymm8, ymm8, ymm12 vpaddd ymm9, ymm9, ymm13 vpaddd ymm10, ymm10, ymm14 vpaddd ymm11, ymm11, ymm15 vpxord ymm4, ymm4, ymm8 vpxord ymm5, ymm5, ymm9 vpxord ymm6, ymm6, ymm10 vpxord ymm7, ymm7, ymm11 vprord ymm4, ymm4, 7 vprord ymm5, ymm5, 7 vprord ymm6, ymm6, 7 vprord ymm7, ymm7, 7 vpaddd ymm0, ymm0, ymm20 vpaddd ymm1, ymm1, ymm27 vpaddd ymm2, ymm2, ymm21 vpaddd ymm3, ymm3, ymm17 vpaddd ymm0, ymm0, ymm5 vpaddd ymm1, ymm1, ymm6 vpaddd ymm2, ymm2, ymm7 vpaddd ymm3, ymm3, ymm4 vpxord ymm15, ymm15, ymm0 vpxord ymm12, ymm12, ymm1 vpxord ymm13, ymm13, ymm2 vpxord ymm14, ymm14, ymm3 vprord ymm15, ymm15, 16 vprord ymm12, ymm12, 16 vprord ymm13, ymm13, 16 vprord ymm14, ymm14, 16 vpaddd ymm10, ymm10, ymm15 vpaddd ymm11, ymm11, ymm12 vpaddd ymm8, ymm8, ymm13 vpaddd ymm9, ymm9, ymm14 vpxord ymm5, ymm5, ymm10 vpxord ymm6, ymm6, ymm11 vpxord ymm7, ymm7, ymm8 vpxord ymm4, ymm4, ymm9 vprord ymm5, ymm5, 12 vprord ymm6, ymm6, 12 vprord ymm7, ymm7, 12 vprord ymm4, ymm4, 12 vpaddd ymm0, ymm0, ymm16 vpaddd ymm1, ymm1, ymm18 vpaddd ymm2, ymm2, ymm24 vpaddd ymm3, ymm3, ymm22 vpaddd ymm0, ymm0, ymm5 vpaddd ymm1, ymm1, ymm6 vpaddd ymm2, ymm2, ymm7 vpaddd ymm3, ymm3, ymm4 vpxord ymm15, ymm15, ymm0 vpxord ymm12, ymm12, ymm1 vpxord ymm13, ymm13, ymm2 vpxord ymm14, ymm14, ymm3 vprord ymm15, ymm15, 8 vprord ymm12, ymm12, 8 vprord ymm13, ymm13, 8 vprord ymm14, ymm14, 8 vpaddd ymm10, ymm10, ymm15 vpaddd ymm11, ymm11, ymm12 vpaddd ymm8, ymm8, ymm13 vpaddd ymm9, ymm9, ymm14 vpxord ymm5, ymm5, ymm10 vpxord ymm6, ymm6, ymm11 vpxord ymm7, ymm7, ymm8 vpxord ymm4, ymm4, ymm9 vprord ymm5, ymm5, 7 vprord ymm6, ymm6, 7 vprord ymm7, ymm7, 7 vprord ymm4, ymm4, 7 vpaddd ymm0, ymm0, ymm28 vpaddd ymm1, ymm1, ymm25 vpaddd ymm2, ymm2, ymm31 vpaddd ymm3, ymm3, ymm30 vpaddd ymm0, ymm0, ymm4 vpaddd ymm1, ymm1, ymm5 vpaddd ymm2, ymm2, ymm6 vpaddd ymm3, ymm3, ymm7 vpxord ymm12, ymm12, ymm0 vpxord ymm13, ymm13, ymm1 vpxord ymm14, ymm14, ymm2 vpxord ymm15, ymm15, ymm3 vprord ymm12, ymm12, 16 vprord ymm13, ymm13, 16 vprord ymm14, ymm14, 16 vprord ymm15, ymm15, 16 vpaddd ymm8, ymm8, ymm12 vpaddd ymm9, ymm9, ymm13 vpaddd ymm10, ymm10, ymm14 vpaddd ymm11, ymm11, ymm15 vpxord ymm4, ymm4, ymm8 vpxord ymm5, ymm5, ymm9 vpxord ymm6, ymm6, ymm10 vpxord ymm7, ymm7, ymm11 vprord ymm4, ymm4, 12 vprord ymm5, ymm5, 12 vprord ymm6, ymm6, 12 vprord ymm7, ymm7, 12 vpaddd ymm0, ymm0, ymm29 vpaddd ymm1, ymm1, ymm27 vpaddd ymm2, ymm2, ymm26 vpaddd ymm3, ymm3, ymm24 vpaddd ymm0, ymm0, ymm4 vpaddd ymm1, ymm1, ymm5 vpaddd ymm2, ymm2, ymm6 vpaddd ymm3, ymm3, ymm7 vpxord ymm12, ymm12, ymm0 vpxord ymm13, ymm13, ymm1 vpxord ymm14, ymm14, ymm2 vpxord ymm15, ymm15, ymm3 vprord ymm12, ymm12, 8 vprord ymm13, ymm13, 8 vprord ymm14, ymm14, 8 vprord ymm15, ymm15, 8 vpaddd ymm8, ymm8, ymm12 vpaddd ymm9, ymm9, ymm13 vpaddd ymm10, ymm10, ymm14 vpaddd ymm11, ymm11, ymm15 vpxord ymm4, ymm4, ymm8 vpxord ymm5, ymm5, ymm9 vpxord ymm6, ymm6, ymm10 vpxord ymm7, ymm7, ymm11 vprord ymm4, ymm4, 7 vprord ymm5, ymm5, 7 vprord ymm6, ymm6, 7 vprord ymm7, ymm7, 7 vpaddd ymm0, ymm0, ymm23 vpaddd ymm1, ymm1, ymm21 vpaddd ymm2, ymm2, ymm16 vpaddd ymm3, ymm3, ymm22 vpaddd ymm0, ymm0, ymm5 vpaddd ymm1, ymm1, ymm6 vpaddd ymm2, ymm2, ymm7 vpaddd ymm3, ymm3, ymm4 vpxord ymm15, ymm15, ymm0 vpxord ymm12, ymm12, ymm1 vpxord ymm13, ymm13, ymm2 vpxord ymm14, ymm14, ymm3 vprord ymm15, ymm15, 16 vprord ymm12, ymm12, 16 vprord ymm13, ymm13, 16 vprord ymm14, ymm14, 16 vpaddd ymm10, ymm10, ymm15 vpaddd ymm11, ymm11, ymm12 vpaddd ymm8, ymm8, ymm13 vpaddd ymm9, ymm9, ymm14 vpxord ymm5, ymm5, ymm10 vpxord ymm6, ymm6, ymm11 vpxord ymm7, ymm7, ymm8 vpxord ymm4, ymm4, ymm9 vprord ymm5, ymm5, 12 vprord ymm6, ymm6, 12 vprord ymm7, ymm7, 12 vprord ymm4, ymm4, 12 vpaddd ymm0, ymm0, ymm18 vpaddd ymm1, ymm1, ymm19 vpaddd ymm2, ymm2, ymm17 vpaddd ymm3, ymm3, ymm20 vpaddd ymm0, ymm0, ymm5 vpaddd ymm1, ymm1, ymm6 vpaddd ymm2, ymm2, ymm7 vpaddd ymm3, ymm3, ymm4 vpxord ymm15, ymm15, ymm0 vpxord ymm12, ymm12, ymm1 vpxord ymm13, ymm13, ymm2 vpxord ymm14, ymm14, ymm3 vprord ymm15, ymm15, 8 vprord ymm12, ymm12, 8 vprord ymm13, ymm13, 8 vprord ymm14, ymm14, 8 vpaddd ymm10, ymm10, ymm15 vpaddd ymm11, ymm11, ymm12 vpaddd ymm8, ymm8, ymm13 vpaddd ymm9, ymm9, ymm14 vpxord ymm5, ymm5, ymm10 vpxord ymm6, ymm6, ymm11 vpxord ymm7, ymm7, ymm8 vpxord ymm4, ymm4, ymm9 vprord ymm5, ymm5, 7 vprord ymm6, ymm6, 7 vprord ymm7, ymm7, 7 vprord ymm4, ymm4, 7 vpaddd ymm0, ymm0, ymm25 vpaddd ymm1, ymm1, ymm27 vpaddd ymm2, ymm2, ymm24 vpaddd ymm3, ymm3, ymm31 vpaddd ymm0, ymm0, ymm4 vpaddd ymm1, ymm1, ymm5 vpaddd ymm2, ymm2, ymm6 vpaddd ymm3, ymm3, ymm7 vpxord ymm12, ymm12, ymm0 vpxord ymm13, ymm13, ymm1 vpxord ymm14, ymm14, ymm2 vpxord ymm15, ymm15, ymm3 vprord ymm12, ymm12, 16 vprord ymm13, ymm13, 16 vprord ymm14, ymm14, 16 vprord ymm15, ymm15, 16 vpaddd ymm8, ymm8, ymm12 vpaddd ymm9, ymm9, ymm13 vpaddd ymm10, ymm10, ymm14 vpaddd ymm11, ymm11, ymm15 vpxord ymm4, ymm4, ymm8 vpxord ymm5, ymm5, ymm9 vpxord ymm6, ymm6, ymm10 vpxord ymm7, ymm7, ymm11 vprord ymm4, ymm4, 12 vprord ymm5, ymm5, 12 vprord ymm6, ymm6, 12 vprord ymm7, ymm7, 12 vpaddd ymm0, ymm0, ymm30 vpaddd ymm1, ymm1, ymm21 vpaddd ymm2, ymm2, ymm28 vpaddd ymm3, ymm3, ymm17 vpaddd ymm0, ymm0, ymm4 vpaddd ymm1, ymm1, ymm5 vpaddd ymm2, ymm2, ymm6 vpaddd ymm3, ymm3, ymm7 vpxord ymm12, ymm12, ymm0 vpxord ymm13, ymm13, ymm1 vpxord ymm14, ymm14, ymm2 vpxord ymm15, ymm15, ymm3 vprord ymm12, ymm12, 8 vprord ymm13, ymm13, 8 vprord ymm14, ymm14, 8 vprord ymm15, ymm15, 8 vpaddd ymm8, ymm8, ymm12 vpaddd ymm9, ymm9, ymm13 vpaddd ymm10, ymm10, ymm14 vpaddd ymm11, ymm11, ymm15 vpxord ymm4, ymm4, ymm8 vpxord ymm5, ymm5, ymm9 vpxord ymm6, ymm6, ymm10 vpxord ymm7, ymm7, ymm11 vprord ymm4, ymm4, 7 vprord ymm5, ymm5, 7 vprord ymm6, ymm6, 7 vprord ymm7, ymm7, 7 vpaddd ymm0, ymm0, ymm29 vpaddd ymm1, ymm1, ymm16 vpaddd ymm2, ymm2, ymm18 vpaddd ymm3, ymm3, ymm20 vpaddd ymm0, ymm0, ymm5 vpaddd ymm1, ymm1, ymm6 vpaddd ymm2, ymm2, ymm7 vpaddd ymm3, ymm3, ymm4 vpxord ymm15, ymm15, ymm0 vpxord ymm12, ymm12, ymm1 vpxord ymm13, ymm13, ymm2 vpxord ymm14, ymm14, ymm3 vprord ymm15, ymm15, 16 vprord ymm12, ymm12, 16 vprord ymm13, ymm13, 16 vprord ymm14, ymm14, 16 vpaddd ymm10, ymm10, ymm15 vpaddd ymm11, ymm11, ymm12 vpaddd ymm8, ymm8, ymm13 vpaddd ymm9, ymm9, ymm14 vpxord ymm5, ymm5, ymm10 vpxord ymm6, ymm6, ymm11 vpxord ymm7, ymm7, ymm8 vpxord ymm4, ymm4, ymm9 vprord ymm5, ymm5, 12 vprord ymm6, ymm6, 12 vprord ymm7, ymm7, 12 vprord ymm4, ymm4, 12 vpaddd ymm0, ymm0, ymm19 vpaddd ymm1, ymm1, ymm26 vpaddd ymm2, ymm2, ymm22 vpaddd ymm3, ymm3, ymm23 vpaddd ymm0, ymm0, ymm5 vpaddd ymm1, ymm1, ymm6 vpaddd ymm2, ymm2, ymm7 vpaddd ymm3, ymm3, ymm4 vpxord ymm15, ymm15, ymm0 vpxord ymm12, ymm12, ymm1 vpxord ymm13, ymm13, ymm2 vpxord ymm14, ymm14, ymm3 vprord ymm15, ymm15, 8 vprord ymm12, ymm12, 8 vprord ymm13, ymm13, 8 vprord ymm14, ymm14, 8 vpaddd ymm10, ymm10, ymm15 vpaddd ymm11, ymm11, ymm12 vpaddd ymm8, ymm8, ymm13 vpaddd ymm9, ymm9, ymm14 vpxord ymm5, ymm5, ymm10 vpxord ymm6, ymm6, ymm11 vpxord ymm7, ymm7, ymm8 vpxord ymm4, ymm4, ymm9 vprord ymm5, ymm5, 7 vprord ymm6, ymm6, 7 vprord ymm7, ymm7, 7 vprord ymm4, ymm4, 7 vpaddd ymm0, ymm0, ymm27 vpaddd ymm1, ymm1, ymm21 vpaddd ymm2, ymm2, ymm17 vpaddd ymm3, ymm3, ymm24 vpaddd ymm0, ymm0, ymm4 vpaddd ymm1, ymm1, ymm5 vpaddd ymm2, ymm2, ymm6 vpaddd ymm3, ymm3, ymm7 vpxord ymm12, ymm12, ymm0 vpxord ymm13, ymm13, ymm1 vpxord ymm14, ymm14, ymm2 vpxord ymm15, ymm15, ymm3 vprord ymm12, ymm12, 16 vprord ymm13, ymm13, 16 vprord ymm14, ymm14, 16 vprord ymm15, ymm15, 16 vpaddd ymm8, ymm8, ymm12 vpaddd ymm9, ymm9, ymm13 vpaddd ymm10, ymm10, ymm14 vpaddd ymm11, ymm11, ymm15 vpxord ymm4, ymm4, ymm8 vpxord ymm5, ymm5, ymm9 vpxord ymm6, ymm6, ymm10 vpxord ymm7, ymm7, ymm11 vprord ymm4, ymm4, 12 vprord ymm5, ymm5, 12 vprord ymm6, ymm6, 12 vprord ymm7, ymm7, 12 vpaddd ymm0, ymm0, ymm31 vpaddd ymm1, ymm1, ymm16 vpaddd ymm2, ymm2, ymm25 vpaddd ymm3, ymm3, ymm22 vpaddd ymm0, ymm0, ymm4 vpaddd ymm1, ymm1, ymm5 vpaddd ymm2, ymm2, ymm6 vpaddd ymm3, ymm3, ymm7 vpxord ymm12, ymm12, ymm0 vpxord ymm13, ymm13, ymm1 vpxord ymm14, ymm14, ymm2 vpxord ymm15, ymm15, ymm3 vprord ymm12, ymm12, 8 vprord ymm13, ymm13, 8 vprord ymm14, ymm14, 8 vprord ymm15, ymm15, 8 vpaddd ymm8, ymm8, ymm12 vpaddd ymm9, ymm9, ymm13 vpaddd ymm10, ymm10, ymm14 vpaddd ymm11, ymm11, ymm15 vpxord ymm4, ymm4, ymm8 vpxord ymm5, ymm5, ymm9 vpxord ymm6, ymm6, ymm10 vpxord ymm7, ymm7, ymm11 vprord ymm4, ymm4, 7 vprord ymm5, ymm5, 7 vprord ymm6, ymm6, 7 vprord ymm7, ymm7, 7 vpaddd ymm0, ymm0, ymm30 vpaddd ymm1, ymm1, ymm18 vpaddd ymm2, ymm2, ymm19 vpaddd ymm3, ymm3, ymm23 vpaddd ymm0, ymm0, ymm5 vpaddd ymm1, ymm1, ymm6 vpaddd ymm2, ymm2, ymm7 vpaddd ymm3, ymm3, ymm4 vpxord ymm15, ymm15, ymm0 vpxord ymm12, ymm12, ymm1 vpxord ymm13, ymm13, ymm2 vpxord ymm14, ymm14, ymm3 vprord ymm15, ymm15, 16 vprord ymm12, ymm12, 16 vprord ymm13, ymm13, 16 vprord ymm14, ymm14, 16 vpaddd ymm10, ymm10, ymm15 vpaddd ymm11, ymm11, ymm12 vpaddd ymm8, ymm8, ymm13 vpaddd ymm9, ymm9, ymm14 vpxord ymm5, ymm5, ymm10 vpxord ymm6, ymm6, ymm11 vpxord ymm7, ymm7, ymm8 vpxord ymm4, ymm4, ymm9 vprord ymm5, ymm5, 12 vprord ymm6, ymm6, 12 vprord ymm7, ymm7, 12 vprord ymm4, ymm4, 12 vpaddd ymm0, ymm0, ymm26 vpaddd ymm1, ymm1, ymm28 vpaddd ymm2, ymm2, ymm20 vpaddd ymm3, ymm3, ymm29 vpaddd ymm0, ymm0, ymm5 vpaddd ymm1, ymm1, ymm6 vpaddd ymm2, ymm2, ymm7 vpaddd ymm3, ymm3, ymm4 vpxord ymm15, ymm15, ymm0 vpxord ymm12, ymm12, ymm1 vpxord ymm13, ymm13, ymm2 vpxord ymm14, ymm14, ymm3 vprord ymm15, ymm15, 8 vprord ymm12, ymm12, 8 vprord ymm13, ymm13, 8 vprord ymm14, ymm14, 8 vpaddd ymm10, ymm10, ymm15 vpaddd ymm11, ymm11, ymm12 vpaddd ymm8, ymm8, ymm13 vpaddd ymm9, ymm9, ymm14 vpxord ymm5, ymm5, ymm10 vpxord ymm6, ymm6, ymm11 vpxord ymm7, ymm7, ymm8 vpxord ymm4, ymm4, ymm9 vprord ymm5, ymm5, 7 vprord ymm6, ymm6, 7 vprord ymm7, ymm7, 7 vprord ymm4, ymm4, 7 vpxor ymm0, ymm0, ymm8 vpxor ymm1, ymm1, ymm9 vpxor ymm2, ymm2, ymm10 vpxor ymm3, ymm3, ymm11 vpxor ymm4, ymm4, ymm12 vpxor ymm5, ymm5, ymm13 vpxor ymm6, ymm6, ymm14 vpxor ymm7, ymm7, ymm15 movzx eax, byte ptr [rbp+0x38] jne 2b mov rbx, qword ptr [rbp+0x50] vunpcklps ymm8, ymm0, ymm1 vunpcklps ymm9, ymm2, ymm3 vunpckhps ymm10, ymm0, ymm1 vunpcklps ymm11, ymm4, ymm5 vunpcklps ymm0, ymm6, ymm7 vshufps ymm12, ymm8, ymm9, 78 vblendps ymm1, ymm8, ymm12, 0xCC vshufps ymm8, ymm11, ymm0, 78 vunpckhps ymm13, ymm2, ymm3 vblendps ymm2, ymm11, ymm8, 0xCC vblendps ymm3, ymm12, ymm9, 0xCC vperm2f128 ymm12, ymm1, ymm2, 0x20 vmovups ymmword ptr [rbx], ymm12 vunpckhps ymm14, ymm4, ymm5 vblendps ymm4, ymm8, ymm0, 0xCC vunpckhps ymm15, ymm6, ymm7 vperm2f128 ymm7, ymm3, ymm4, 0x20 vmovups ymmword ptr [rbx+0x20], ymm7 vshufps ymm5, ymm10, ymm13, 78 vblendps ymm6, ymm5, ymm13, 0xCC vshufps ymm13, ymm14, ymm15, 78 vblendps ymm10, ymm10, ymm5, 0xCC vblendps ymm14, ymm14, ymm13, 0xCC vperm2f128 ymm8, ymm10, ymm14, 0x20 vmovups ymmword ptr [rbx+0x40], ymm8 vblendps ymm15, ymm13, ymm15, 0xCC vperm2f128 ymm13, ymm6, ymm15, 0x20 vmovups ymmword ptr [rbx+0x60], ymm13 vperm2f128 ymm9, ymm1, ymm2, 0x31 vperm2f128 ymm11, ymm3, ymm4, 0x31 vmovups ymmword ptr [rbx+0x80], ymm9 vperm2f128 ymm14, ymm10, ymm14, 0x31 vperm2f128 ymm15, ymm6, ymm15, 0x31 vmovups ymmword ptr [rbx+0xA0], ymm11 vmovups ymmword ptr [rbx+0xC0], ymm14 vmovups ymmword ptr [rbx+0xE0], ymm15 vmovdqa ymm0, ymmword ptr [rsp] vmovdqa ymm2, ymmword ptr [rsp+0x2*0x20] vmovdqa32 ymm0 {k1}, ymmword ptr [rsp+0x1*0x20] vmovdqa32 ymm2 {k1}, ymmword ptr [rsp+0x3*0x20] vmovdqa ymmword ptr [rsp], ymm0 vmovdqa ymmword ptr [rsp+0x2*0x20], ymm2 add rbx, 256 mov qword ptr [rbp+0x50], rbx add rdi, 64 sub rsi, 8 3: mov rbx, qword ptr [rbp+0x50] mov r15, qword ptr [rsp+0x80] movzx r13, byte ptr [rbp+0x38] movzx r12, byte ptr [rbp+0x48] test esi, 0x4 je 3f vbroadcasti32x4 zmm0, xmmword ptr [rcx] vbroadcasti32x4 zmm1, xmmword ptr [rcx+0x1*0x10] vmovdqa xmm12, xmmword ptr [rsp] vmovdqa xmm13, xmmword ptr [rsp+0x4*0x10] vpunpckldq xmm14, xmm12, xmm13 vpunpckhdq xmm15, xmm12, xmm13 vpermq ymm14, ymm14, 0xDC vpermq ymm15, ymm15, 0xDC vpbroadcastd zmm12, dword ptr [BLAKE3_BLOCK_LEN+rip] vinserti64x4 zmm13, zmm14, ymm15, 0x01 mov eax, 17476 kmovw k2, eax vpblendmd zmm13 {k2}, zmm13, zmm12 vbroadcasti32x4 zmm15, xmmword ptr [BLAKE3_IV+rip] mov r8, qword ptr [rdi] mov r9, qword ptr [rdi+0x8] mov r10, qword ptr [rdi+0x10] mov r11, qword ptr [rdi+0x18] mov eax, 43690 kmovw k3, eax mov eax, 34952 kmovw k4, eax movzx eax, byte ptr [rbp+0x40] or eax, r13d xor edx, edx .p2align 5 2: mov r14d, eax or eax, r12d add rdx, 64 cmp rdx, r15 cmovne eax, r14d mov dword ptr [rsp+0x88], eax vmovdqa32 zmm2, zmm15 vpbroadcastd zmm8, dword ptr [rsp+0x22*0x4] vpblendmd zmm3 {k4}, zmm13, zmm8 vmovups zmm8, zmmword ptr [r8+rdx-0x1*0x40] vinserti32x4 zmm8, zmm8, xmmword ptr [r9+rdx-0x4*0x10], 0x01 vinserti32x4 zmm8, zmm8, xmmword ptr [r10+rdx-0x4*0x10], 0x02 vinserti32x4 zmm8, zmm8, xmmword ptr [r11+rdx-0x4*0x10], 0x03 vmovups zmm9, zmmword ptr [r8+rdx-0x30] vinserti32x4 zmm9, zmm9, xmmword ptr [r9+rdx-0x3*0x10], 0x01 vinserti32x4 zmm9, zmm9, xmmword ptr [r10+rdx-0x3*0x10], 0x02 vinserti32x4 zmm9, zmm9, xmmword ptr [r11+rdx-0x3*0x10], 0x03 vshufps zmm4, zmm8, zmm9, 136 vshufps zmm5, zmm8, zmm9, 221 vmovups zmm8, zmmword ptr [r8+rdx-0x20] vinserti32x4 zmm8, zmm8, xmmword ptr [r9+rdx-0x2*0x10], 0x01 vinserti32x4 zmm8, zmm8, xmmword ptr [r10+rdx-0x2*0x10], 0x02 vinserti32x4 zmm8, zmm8, xmmword ptr [r11+rdx-0x2*0x10], 0x03 vmovups zmm9, zmmword ptr [r8+rdx-0x10] vinserti32x4 zmm9, zmm9, xmmword ptr [r9+rdx-0x1*0x10], 0x01 vinserti32x4 zmm9, zmm9, xmmword ptr [r10+rdx-0x1*0x10], 0x02 vinserti32x4 zmm9, zmm9, xmmword ptr [r11+rdx-0x1*0x10], 0x03 vshufps zmm6, zmm8, zmm9, 136 vshufps zmm7, zmm8, zmm9, 221 vpshufd zmm6, zmm6, 0x93 vpshufd zmm7, zmm7, 0x93 mov al, 7 9: vpaddd zmm0, zmm0, zmm4 vpaddd zmm0, zmm0, zmm1 vpxord zmm3, zmm3, zmm0 vprord zmm3, zmm3, 16 vpaddd zmm2, zmm2, zmm3 vpxord zmm1, zmm1, zmm2 vprord zmm1, zmm1, 12 vpaddd zmm0, zmm0, zmm5 vpaddd zmm0, zmm0, zmm1 vpxord zmm3, zmm3, zmm0 vprord zmm3, zmm3, 8 vpaddd zmm2, zmm2, zmm3 vpxord zmm1, zmm1, zmm2 vprord zmm1, zmm1, 7 vpshufd zmm0, zmm0, 0x93 vpshufd zmm3, zmm3, 0x4E vpshufd zmm2, zmm2, 0x39 vpaddd zmm0, zmm0, zmm6 vpaddd zmm0, zmm0, zmm1 vpxord zmm3, zmm3, zmm0 vprord zmm3, zmm3, 16 vpaddd zmm2, zmm2, zmm3 vpxord zmm1, zmm1, zmm2 vprord zmm1, zmm1, 12 vpaddd zmm0, zmm0, zmm7 vpaddd zmm0, zmm0, zmm1 vpxord zmm3, zmm3, zmm0 vprord zmm3, zmm3, 8 vpaddd zmm2, zmm2, zmm3 vpxord zmm1, zmm1, zmm2 vprord zmm1, zmm1, 7 vpshufd zmm0, zmm0, 0x39 vpshufd zmm3, zmm3, 0x4E vpshufd zmm2, zmm2, 0x93 dec al jz 9f vshufps zmm8, zmm4, zmm5, 214 vpshufd zmm9, zmm4, 0x0F vpshufd zmm4, zmm8, 0x39 vshufps zmm8, zmm6, zmm7, 250 vpblendmd zmm9 {k3}, zmm9, zmm8 vpunpcklqdq zmm8, zmm7, zmm5 vpblendmd zmm8 {k4}, zmm8, zmm6 vpshufd zmm8, zmm8, 0x78 vpunpckhdq zmm5, zmm5, zmm7 vpunpckldq zmm6, zmm6, zmm5 vpshufd zmm7, zmm6, 0x1E vmovdqa32 zmm5, zmm9 vmovdqa32 zmm6, zmm8 jmp 9b 9: vpxord zmm0, zmm0, zmm2 vpxord zmm1, zmm1, zmm3 mov eax, r13d cmp rdx, r15 jne 2b vmovdqu xmmword ptr [rbx], xmm0 vmovdqu xmmword ptr [rbx+0x10], xmm1 vextracti128 xmmword ptr [rbx+0x20], ymm0, 0x01 vextracti128 xmmword ptr [rbx+0x30], ymm1, 0x01 vextracti32x4 xmmword ptr [rbx+0x4*0x10], zmm0, 0x02 vextracti32x4 xmmword ptr [rbx+0x5*0x10], zmm1, 0x02 vextracti32x4 xmmword ptr [rbx+0x6*0x10], zmm0, 0x03 vextracti32x4 xmmword ptr [rbx+0x7*0x10], zmm1, 0x03 vmovdqa xmm0, xmmword ptr [rsp] vmovdqa xmm2, xmmword ptr [rsp+0x40] vmovdqa32 xmm0 {k1}, xmmword ptr [rsp+0x1*0x10] vmovdqa32 xmm2 {k1}, xmmword ptr [rsp+0x5*0x10] vmovdqa xmmword ptr [rsp], xmm0 vmovdqa xmmword ptr [rsp+0x40], xmm2 add rbx, 128 add rdi, 32 sub rsi, 4 3: test esi, 0x2 je 3f vbroadcasti128 ymm0, xmmword ptr [rcx] vbroadcasti128 ymm1, xmmword ptr [rcx+0x10] vmovd xmm13, dword ptr [rsp] vpinsrd xmm13, xmm13, dword ptr [rsp+0x40], 1 vpinsrd xmm13, xmm13, dword ptr [BLAKE3_BLOCK_LEN+rip], 2 vmovd xmm14, dword ptr [rsp+0x4] vpinsrd xmm14, xmm14, dword ptr [rsp+0x44], 1 vpinsrd xmm14, xmm14, dword ptr [BLAKE3_BLOCK_LEN+rip], 2 vinserti128 ymm13, ymm13, xmm14, 0x01 mov r8, qword ptr [rdi] mov r9, qword ptr [rdi+0x8] movzx eax, byte ptr [rbp+0x40] or eax, r13d xor edx, edx .p2align 5 2: mov r14d, eax or eax, r12d add rdx, 64 cmp rdx, r15 cmovne eax, r14d mov dword ptr [rsp+0x88], eax vbroadcasti128 ymm2, xmmword ptr [BLAKE3_IV+rip] vpbroadcastd ymm8, dword ptr [rsp+0x88] vpblendd ymm3, ymm13, ymm8, 0x88 vmovups ymm8, ymmword ptr [r8+rdx-0x40] vinsertf128 ymm8, ymm8, xmmword ptr [r9+rdx-0x40], 0x01 vmovups ymm9, ymmword ptr [r8+rdx-0x30] vinsertf128 ymm9, ymm9, xmmword ptr [r9+rdx-0x30], 0x01 vshufps ymm4, ymm8, ymm9, 136 vshufps ymm5, ymm8, ymm9, 221 vmovups ymm8, ymmword ptr [r8+rdx-0x20] vinsertf128 ymm8, ymm8, xmmword ptr [r9+rdx-0x20], 0x01 vmovups ymm9, ymmword ptr [r8+rdx-0x10] vinsertf128 ymm9, ymm9, xmmword ptr [r9+rdx-0x10], 0x01 vshufps ymm6, ymm8, ymm9, 136 vshufps ymm7, ymm8, ymm9, 221 vpshufd ymm6, ymm6, 0x93 vpshufd ymm7, ymm7, 0x93 mov al, 7 9: vpaddd ymm0, ymm0, ymm4 vpaddd ymm0, ymm0, ymm1 vpxord ymm3, ymm3, ymm0 vprord ymm3, ymm3, 16 vpaddd ymm2, ymm2, ymm3 vpxord ymm1, ymm1, ymm2 vprord ymm1, ymm1, 12 vpaddd ymm0, ymm0, ymm5 vpaddd ymm0, ymm0, ymm1 vpxord ymm3, ymm3, ymm0 vprord ymm3, ymm3, 8 vpaddd ymm2, ymm2, ymm3 vpxord ymm1, ymm1, ymm2 vprord ymm1, ymm1, 7 vpshufd ymm0, ymm0, 0x93 vpshufd ymm3, ymm3, 0x4E vpshufd ymm2, ymm2, 0x39 vpaddd ymm0, ymm0, ymm6 vpaddd ymm0, ymm0, ymm1 vpxord ymm3, ymm3, ymm0 vprord ymm3, ymm3, 16 vpaddd ymm2, ymm2, ymm3 vpxord ymm1, ymm1, ymm2 vprord ymm1, ymm1, 12 vpaddd ymm0, ymm0, ymm7 vpaddd ymm0, ymm0, ymm1 vpxord ymm3, ymm3, ymm0 vprord ymm3, ymm3, 8 vpaddd ymm2, ymm2, ymm3 vpxord ymm1, ymm1, ymm2 vprord ymm1, ymm1, 7 vpshufd ymm0, ymm0, 0x39 vpshufd ymm3, ymm3, 0x4E vpshufd ymm2, ymm2, 0x93 dec al jz 9f vshufps ymm8, ymm4, ymm5, 214 vpshufd ymm9, ymm4, 0x0F vpshufd ymm4, ymm8, 0x39 vshufps ymm8, ymm6, ymm7, 250 vpblendd ymm9, ymm9, ymm8, 0xAA vpunpcklqdq ymm8, ymm7, ymm5 vpblendd ymm8, ymm8, ymm6, 0x88 vpshufd ymm8, ymm8, 0x78 vpunpckhdq ymm5, ymm5, ymm7 vpunpckldq ymm6, ymm6, ymm5 vpshufd ymm7, ymm6, 0x1E vmovdqa ymm5, ymm9 vmovdqa ymm6, ymm8 jmp 9b 9: vpxor ymm0, ymm0, ymm2 vpxor ymm1, ymm1, ymm3 mov eax, r13d cmp rdx, r15 jne 2b vmovdqu xmmword ptr [rbx], xmm0 vmovdqu xmmword ptr [rbx+0x10], xmm1 vextracti128 xmmword ptr [rbx+0x20], ymm0, 0x01 vextracti128 xmmword ptr [rbx+0x30], ymm1, 0x01 vmovdqa xmm0, xmmword ptr [rsp] vmovdqa xmm2, xmmword ptr [rsp+0x4*0x10] vmovdqu32 xmm0 {k1}, xmmword ptr [rsp+0x8] vmovdqu32 xmm2 {k1}, xmmword ptr [rsp+0x48] vmovdqa xmmword ptr [rsp], xmm0 vmovdqa xmmword ptr [rsp+0x4*0x10], xmm2 add rbx, 64 add rdi, 16 sub rsi, 2 3: test esi, 0x1 je 4b vmovdqu xmm0, xmmword ptr [rcx] vmovdqu xmm1, xmmword ptr [rcx+0x10] vmovd xmm14, dword ptr [rsp] vpinsrd xmm14, xmm14, dword ptr [rsp+0x40], 1 vpinsrd xmm14, xmm14, dword ptr [BLAKE3_BLOCK_LEN+rip], 2 vmovdqa xmm15, xmmword ptr [BLAKE3_IV+rip] mov r8, qword ptr [rdi] movzx eax, byte ptr [rbp+0x40] or eax, r13d xor edx, edx .p2align 5 2: mov r14d, eax or eax, r12d add rdx, 64 cmp rdx, r15 cmovne eax, r14d vpinsrd xmm3, xmm14, eax, 3 vmovdqa xmm2, xmm15 vmovups xmm8, xmmword ptr [r8+rdx-0x40] vmovups xmm9, xmmword ptr [r8+rdx-0x30] vshufps xmm4, xmm8, xmm9, 136 vshufps xmm5, xmm8, xmm9, 221 vmovups xmm8, xmmword ptr [r8+rdx-0x20] vmovups xmm9, xmmword ptr [r8+rdx-0x10] vshufps xmm6, xmm8, xmm9, 136 vshufps xmm7, xmm8, xmm9, 221 vpshufd xmm6, xmm6, 0x93 vpshufd xmm7, xmm7, 0x93 mov al, 7 9: vpaddd xmm0, xmm0, xmm4 vpaddd xmm0, xmm0, xmm1 vpxord xmm3, xmm3, xmm0 vprord xmm3, xmm3, 16 vpaddd xmm2, xmm2, xmm3 vpxord xmm1, xmm1, xmm2 vprord xmm1, xmm1, 12 vpaddd xmm0, xmm0, xmm5 vpaddd xmm0, xmm0, xmm1 vpxord xmm3, xmm3, xmm0 vprord xmm3, xmm3, 8 vpaddd xmm2, xmm2, xmm3 vpxord xmm1, xmm1, xmm2 vprord xmm1, xmm1, 7 vpshufd xmm0, xmm0, 0x93 vpshufd xmm3, xmm3, 0x4E vpshufd xmm2, xmm2, 0x39 vpaddd xmm0, xmm0, xmm6 vpaddd xmm0, xmm0, xmm1 vpxord xmm3, xmm3, xmm0 vprord xmm3, xmm3, 16 vpaddd xmm2, xmm2, xmm3 vpxord xmm1, xmm1, xmm2 vprord xmm1, xmm1, 12 vpaddd xmm0, xmm0, xmm7 vpaddd xmm0, xmm0, xmm1 vpxord xmm3, xmm3, xmm0 vprord xmm3, xmm3, 8 vpaddd xmm2, xmm2, xmm3 vpxord xmm1, xmm1, xmm2 vprord xmm1, xmm1, 7 vpshufd xmm0, xmm0, 0x39 vpshufd xmm3, xmm3, 0x4E vpshufd xmm2, xmm2, 0x93 dec al jz 9f vshufps xmm8, xmm4, xmm5, 214 vpshufd xmm9, xmm4, 0x0F vpshufd xmm4, xmm8, 0x39 vshufps xmm8, xmm6, xmm7, 250 vpblendd xmm9, xmm9, xmm8, 0xAA vpunpcklqdq xmm8, xmm7, xmm5 vpblendd xmm8, xmm8, xmm6, 0x88 vpshufd xmm8, xmm8, 0x78 vpunpckhdq xmm5, xmm5, xmm7 vpunpckldq xmm6, xmm6, xmm5 vpshufd xmm7, xmm6, 0x1E vmovdqa xmm5, xmm9 vmovdqa xmm6, xmm8 jmp 9b 9: vpxor xmm0, xmm0, xmm2 vpxor xmm1, xmm1, xmm3 mov eax, r13d cmp rdx, r15 jne 2b vmovdqu xmmword ptr [rbx], xmm0 vmovdqu xmmword ptr [rbx+0x10], xmm1 jmp 4b .p2align 6 _blake3_compress_in_place_avx512: blake3_compress_in_place_avx512: _CET_ENDBR vmovdqu xmm0, xmmword ptr [rdi] vmovdqu xmm1, xmmword ptr [rdi+0x10] movzx eax, r8b movzx edx, dl shl rax, 32 add rdx, rax vmovq xmm3, rcx vmovq xmm4, rdx vpunpcklqdq xmm3, xmm3, xmm4 vmovaps xmm2, xmmword ptr [BLAKE3_IV+rip] vmovups xmm8, xmmword ptr [rsi] vmovups xmm9, xmmword ptr [rsi+0x10] vshufps xmm4, xmm8, xmm9, 136 vshufps xmm5, xmm8, xmm9, 221 vmovups xmm8, xmmword ptr [rsi+0x20] vmovups xmm9, xmmword ptr [rsi+0x30] vshufps xmm6, xmm8, xmm9, 136 vshufps xmm7, xmm8, xmm9, 221 vpshufd xmm6, xmm6, 0x93 vpshufd xmm7, xmm7, 0x93 mov al, 7 9: vpaddd xmm0, xmm0, xmm4 vpaddd xmm0, xmm0, xmm1 vpxord xmm3, xmm3, xmm0 vprord xmm3, xmm3, 16 vpaddd xmm2, xmm2, xmm3 vpxord xmm1, xmm1, xmm2 vprord xmm1, xmm1, 12 vpaddd xmm0, xmm0, xmm5 vpaddd xmm0, xmm0, xmm1 vpxord xmm3, xmm3, xmm0 vprord xmm3, xmm3, 8 vpaddd xmm2, xmm2, xmm3 vpxord xmm1, xmm1, xmm2 vprord xmm1, xmm1, 7 vpshufd xmm0, xmm0, 0x93 vpshufd xmm3, xmm3, 0x4E vpshufd xmm2, xmm2, 0x39 vpaddd xmm0, xmm0, xmm6 vpaddd xmm0, xmm0, xmm1 vpxord xmm3, xmm3, xmm0 vprord xmm3, xmm3, 16 vpaddd xmm2, xmm2, xmm3 vpxord xmm1, xmm1, xmm2 vprord xmm1, xmm1, 12 vpaddd xmm0, xmm0, xmm7 vpaddd xmm0, xmm0, xmm1 vpxord xmm3, xmm3, xmm0 vprord xmm3, xmm3, 8 vpaddd xmm2, xmm2, xmm3 vpxord xmm1, xmm1, xmm2 vprord xmm1, xmm1, 7 vpshufd xmm0, xmm0, 0x39 vpshufd xmm3, xmm3, 0x4E vpshufd xmm2, xmm2, 0x93 dec al jz 9f vshufps xmm8, xmm4, xmm5, 214 vpshufd xmm9, xmm4, 0x0F vpshufd xmm4, xmm8, 0x39 vshufps xmm8, xmm6, xmm7, 250 vpblendd xmm9, xmm9, xmm8, 0xAA vpunpcklqdq xmm8, xmm7, xmm5 vpblendd xmm8, xmm8, xmm6, 0x88 vpshufd xmm8, xmm8, 0x78 vpunpckhdq xmm5, xmm5, xmm7 vpunpckldq xmm6, xmm6, xmm5 vpshufd xmm7, xmm6, 0x1E vmovdqa xmm5, xmm9 vmovdqa xmm6, xmm8 jmp 9b 9: vpxor xmm0, xmm0, xmm2 vpxor xmm1, xmm1, xmm3 vmovdqu xmmword ptr [rdi], xmm0 vmovdqu xmmword ptr [rdi+0x10], xmm1 ret .p2align 6 _blake3_compress_xof_avx512: blake3_compress_xof_avx512: _CET_ENDBR vmovdqu xmm0, xmmword ptr [rdi] vmovdqu xmm1, xmmword ptr [rdi+0x10] movzx eax, r8b movzx edx, dl shl rax, 32 add rdx, rax vmovq xmm3, rcx vmovq xmm4, rdx vpunpcklqdq xmm3, xmm3, xmm4 vmovaps xmm2, xmmword ptr [BLAKE3_IV+rip] vmovups xmm8, xmmword ptr [rsi] vmovups xmm9, xmmword ptr [rsi+0x10] vshufps xmm4, xmm8, xmm9, 136 vshufps xmm5, xmm8, xmm9, 221 vmovups xmm8, xmmword ptr [rsi+0x20] vmovups xmm9, xmmword ptr [rsi+0x30] vshufps xmm6, xmm8, xmm9, 136 vshufps xmm7, xmm8, xmm9, 221 vpshufd xmm6, xmm6, 0x93 vpshufd xmm7, xmm7, 0x93 mov al, 7 9: vpaddd xmm0, xmm0, xmm4 vpaddd xmm0, xmm0, xmm1 vpxord xmm3, xmm3, xmm0 vprord xmm3, xmm3, 16 vpaddd xmm2, xmm2, xmm3 vpxord xmm1, xmm1, xmm2 vprord xmm1, xmm1, 12 vpaddd xmm0, xmm0, xmm5 vpaddd xmm0, xmm0, xmm1 vpxord xmm3, xmm3, xmm0 vprord xmm3, xmm3, 8 vpaddd xmm2, xmm2, xmm3 vpxord xmm1, xmm1, xmm2 vprord xmm1, xmm1, 7 vpshufd xmm0, xmm0, 0x93 vpshufd xmm3, xmm3, 0x4E vpshufd xmm2, xmm2, 0x39 vpaddd xmm0, xmm0, xmm6 vpaddd xmm0, xmm0, xmm1 vpxord xmm3, xmm3, xmm0 vprord xmm3, xmm3, 16 vpaddd xmm2, xmm2, xmm3 vpxord xmm1, xmm1, xmm2 vprord xmm1, xmm1, 12 vpaddd xmm0, xmm0, xmm7 vpaddd xmm0, xmm0, xmm1 vpxord xmm3, xmm3, xmm0 vprord xmm3, xmm3, 8 vpaddd xmm2, xmm2, xmm3 vpxord xmm1, xmm1, xmm2 vprord xmm1, xmm1, 7 vpshufd xmm0, xmm0, 0x39 vpshufd xmm3, xmm3, 0x4E vpshufd xmm2, xmm2, 0x93 dec al jz 9f vshufps xmm8, xmm4, xmm5, 214 vpshufd xmm9, xmm4, 0x0F vpshufd xmm4, xmm8, 0x39 vshufps xmm8, xmm6, xmm7, 250 vpblendd xmm9, xmm9, xmm8, 0xAA vpunpcklqdq xmm8, xmm7, xmm5 vpblendd xmm8, xmm8, xmm6, 0x88 vpshufd xmm8, xmm8, 0x78 vpunpckhdq xmm5, xmm5, xmm7 vpunpckldq xmm6, xmm6, xmm5 vpshufd xmm7, xmm6, 0x1E vmovdqa xmm5, xmm9 vmovdqa xmm6, xmm8 jmp 9b 9: vpxor xmm0, xmm0, xmm2 vpxor xmm1, xmm1, xmm3 vpxor xmm2, xmm2, [rdi] vpxor xmm3, xmm3, [rdi+0x10] vmovdqu xmmword ptr [r9], xmm0 vmovdqu xmmword ptr [r9+0x10], xmm1 vmovdqu xmmword ptr [r9+0x20], xmm2 vmovdqu xmmword ptr [r9+0x30], xmm3 ret .p2align 6 blake3_xof_many_avx512: _blake3_xof_many_avx512: _CET_ENDBR mov r10,QWORD PTR [rsp+0x8] cmp r10,0x1 ja 2f vmovdqu xmm0,XMMWORD PTR [rdi] vmovdqu xmm1,XMMWORD PTR [rdi+0x10] movzx eax,r8b movzx edx,dl shl rax,0x20 add rdx,rax vmovq xmm3,rcx vmovq xmm4,rdx vpunpcklqdq xmm3,xmm3,xmm4 vmovaps xmm2,XMMWORD PTR [BLAKE3_IV+rip] vmovups xmm8,XMMWORD PTR [rsi] vmovups xmm9,XMMWORD PTR [rsi+0x10] vshufps xmm4,xmm8,xmm9,0x88 vshufps xmm5,xmm8,xmm9,0xdd vmovups xmm8,XMMWORD PTR [rsi+0x20] vmovups xmm9,XMMWORD PTR [rsi+0x30] vshufps xmm6,xmm8,xmm9,0x88 vshufps xmm7,xmm8,xmm9,0xdd vpshufd xmm6,xmm6,0x93 vpshufd xmm7,xmm7,0x93 mov al,0x7 3: vpaddd xmm0,xmm0,xmm4 vpaddd xmm0,xmm0,xmm1 vpxord xmm3,xmm3,xmm0 vprord xmm3,xmm3,0x10 vpaddd xmm2,xmm2,xmm3 vpxord xmm1,xmm1,xmm2 vprord xmm1,xmm1,0xc vpaddd xmm0,xmm0,xmm5 vpaddd xmm0,xmm0,xmm1 vpxord xmm3,xmm3,xmm0 vprord xmm3,xmm3,0x8 vpaddd xmm2,xmm2,xmm3 vpxord xmm1,xmm1,xmm2 vprord xmm1,xmm1,0x7 vpshufd xmm0,xmm0,0x93 vpshufd xmm3,xmm3,0x4e vpshufd xmm2,xmm2,0x39 vpaddd xmm0,xmm0,xmm6 vpaddd xmm0,xmm0,xmm1 vpxord xmm3,xmm3,xmm0 vprord xmm3,xmm3,0x10 vpaddd xmm2,xmm2,xmm3 vpxord xmm1,xmm1,xmm2 vprord xmm1,xmm1,0xc vpaddd xmm0,xmm0,xmm7 vpaddd xmm0,xmm0,xmm1 vpxord xmm3,xmm3,xmm0 vprord xmm3,xmm3,0x8 vpaddd xmm2,xmm2,xmm3 vpxord xmm1,xmm1,xmm2 vprord xmm1,xmm1,0x7 vpshufd xmm0,xmm0,0x39 vpshufd xmm3,xmm3,0x4e vpshufd xmm2,xmm2,0x93 dec al je 3f vshufps xmm8,xmm4,xmm5,0xd6 vpshufd xmm9,xmm4,0xf vpshufd xmm4,xmm8,0x39 vshufps xmm8,xmm6,xmm7,0xfa vpblendd xmm9,xmm9,xmm8,0xaa vpunpcklqdq xmm8,xmm7,xmm5 vpblendd xmm8,xmm8,xmm6,0x88 vpshufd xmm8,xmm8,0x78 vpunpckhdq xmm5,xmm5,xmm7 vpunpckldq xmm6,xmm6,xmm5 vpshufd xmm7,xmm6,0x1e vmovdqa xmm5,xmm9 vmovdqa xmm6,xmm8 jmp 3b 3: vpxor xmm0,xmm0,xmm2 vpxor xmm1,xmm1,xmm3 vpxor xmm2,xmm2,XMMWORD PTR [rdi] vpxor xmm3,xmm3,XMMWORD PTR [rdi+0x10] vmovdqu XMMWORD PTR [r9],xmm0 vmovdqu XMMWORD PTR [r9+0x10],xmm1 vmovdqu XMMWORD PTR [r9+0x20],xmm2 vmovdqu XMMWORD PTR [r9+0x30],xmm3 ret .p2align 6 2: push rbp mov rbp,rsp sub rsp,0x90 and rsp,0xffffffffffffffc0 vpbroadcastd zmm0,ecx shr rcx,0x20 vpbroadcastd zmm1,ecx vpaddd zmm2,zmm0,ZMMWORD PTR [ADD0+rip] vpcmpltud k1,zmm2,zmm0 vpaddd zmm1{k1},zmm1,DWORD PTR [ADD1+rip]{1to16} vmovdqa32 ZMMWORD PTR [rsp],zmm2 vmovdqa32 ZMMWORD PTR [rsp+0x40],zmm1 cmp r10,0x10 jb 2f 3: vpbroadcastd zmm16,DWORD PTR [rsi] vpbroadcastd zmm17,DWORD PTR [rsi+0x4] vpbroadcastd zmm18,DWORD PTR [rsi+0x8] vpbroadcastd zmm19,DWORD PTR [rsi+0xc] vpbroadcastd zmm20,DWORD PTR [rsi+0x10] vpbroadcastd zmm21,DWORD PTR [rsi+0x14] vpbroadcastd zmm22,DWORD PTR [rsi+0x18] vpbroadcastd zmm23,DWORD PTR [rsi+0x1c] vpbroadcastd zmm24,DWORD PTR [rsi+0x20] vpbroadcastd zmm25,DWORD PTR [rsi+0x24] vpbroadcastd zmm26,DWORD PTR [rsi+0x28] vpbroadcastd zmm27,DWORD PTR [rsi+0x2c] vpbroadcastd zmm28,DWORD PTR [rsi+0x30] vpbroadcastd zmm29,DWORD PTR [rsi+0x34] vpbroadcastd zmm30,DWORD PTR [rsi+0x38] vpbroadcastd zmm31,DWORD PTR [rsi+0x3c] vpbroadcastd zmm0,DWORD PTR [rdi] vpbroadcastd zmm1,DWORD PTR [rdi+0x4] vpbroadcastd zmm2,DWORD PTR [rdi+0x8] vpbroadcastd zmm3,DWORD PTR [rdi+0xc] vpbroadcastd zmm4,DWORD PTR [rdi+0x10] vpbroadcastd zmm5,DWORD PTR [rdi+0x14] vpbroadcastd zmm6,DWORD PTR [rdi+0x18] vpbroadcastd zmm7,DWORD PTR [rdi+0x1c] vpbroadcastd zmm8,DWORD PTR [BLAKE3_IV_0+rip] vpbroadcastd zmm9,DWORD PTR [BLAKE3_IV_1+rip] vpbroadcastd zmm10,DWORD PTR [BLAKE3_IV_2+rip] vpbroadcastd zmm11,DWORD PTR [BLAKE3_IV_3+rip] vmovdqa32 zmm12,ZMMWORD PTR [rsp] vmovdqa32 zmm13,ZMMWORD PTR [rsp+0x40] vpbroadcastd zmm14,edx vpbroadcastd zmm15,r8d vpaddd zmm0,zmm0,zmm16 vpaddd zmm1,zmm1,zmm18 vpaddd zmm2,zmm2,zmm20 vpaddd zmm3,zmm3,zmm22 vpaddd zmm0,zmm0,zmm4 vpaddd zmm1,zmm1,zmm5 vpaddd zmm2,zmm2,zmm6 vpaddd zmm3,zmm3,zmm7 vpxord zmm12,zmm12,zmm0 vpxord zmm13,zmm13,zmm1 vpxord zmm14,zmm14,zmm2 vpxord zmm15,zmm15,zmm3 vprord zmm12,zmm12,0x10 vprord zmm13,zmm13,0x10 vprord zmm14,zmm14,0x10 vprord zmm15,zmm15,0x10 vpaddd zmm8,zmm8,zmm12 vpaddd zmm9,zmm9,zmm13 vpaddd zmm10,zmm10,zmm14 vpaddd zmm11,zmm11,zmm15 vpxord zmm4,zmm4,zmm8 vpxord zmm5,zmm5,zmm9 vpxord zmm6,zmm6,zmm10 vpxord zmm7,zmm7,zmm11 vprord zmm4,zmm4,0xc vprord zmm5,zmm5,0xc vprord zmm6,zmm6,0xc vprord zmm7,zmm7,0xc vpaddd zmm0,zmm0,zmm17 vpaddd zmm1,zmm1,zmm19 vpaddd zmm2,zmm2,zmm21 vpaddd zmm3,zmm3,zmm23 vpaddd zmm0,zmm0,zmm4 vpaddd zmm1,zmm1,zmm5 vpaddd zmm2,zmm2,zmm6 vpaddd zmm3,zmm3,zmm7 vpxord zmm12,zmm12,zmm0 vpxord zmm13,zmm13,zmm1 vpxord zmm14,zmm14,zmm2 vpxord zmm15,zmm15,zmm3 vprord zmm12,zmm12,0x8 vprord zmm13,zmm13,0x8 vprord zmm14,zmm14,0x8 vprord zmm15,zmm15,0x8 vpaddd zmm8,zmm8,zmm12 vpaddd zmm9,zmm9,zmm13 vpaddd zmm10,zmm10,zmm14 vpaddd zmm11,zmm11,zmm15 vpxord zmm4,zmm4,zmm8 vpxord zmm5,zmm5,zmm9 vpxord zmm6,zmm6,zmm10 vpxord zmm7,zmm7,zmm11 vprord zmm4,zmm4,0x7 vprord zmm5,zmm5,0x7 vprord zmm6,zmm6,0x7 vprord zmm7,zmm7,0x7 vpaddd zmm0,zmm0,zmm24 vpaddd zmm1,zmm1,zmm26 vpaddd zmm2,zmm2,zmm28 vpaddd zmm3,zmm3,zmm30 vpaddd zmm0,zmm0,zmm5 vpaddd zmm1,zmm1,zmm6 vpaddd zmm2,zmm2,zmm7 vpaddd zmm3,zmm3,zmm4 vpxord zmm15,zmm15,zmm0 vpxord zmm12,zmm12,zmm1 vpxord zmm13,zmm13,zmm2 vpxord zmm14,zmm14,zmm3 vprord zmm15,zmm15,0x10 vprord zmm12,zmm12,0x10 vprord zmm13,zmm13,0x10 vprord zmm14,zmm14,0x10 vpaddd zmm10,zmm10,zmm15 vpaddd zmm11,zmm11,zmm12 vpaddd zmm8,zmm8,zmm13 vpaddd zmm9,zmm9,zmm14 vpxord zmm5,zmm5,zmm10 vpxord zmm6,zmm6,zmm11 vpxord zmm7,zmm7,zmm8 vpxord zmm4,zmm4,zmm9 vprord zmm5,zmm5,0xc vprord zmm6,zmm6,0xc vprord zmm7,zmm7,0xc vprord zmm4,zmm4,0xc vpaddd zmm0,zmm0,zmm25 vpaddd zmm1,zmm1,zmm27 vpaddd zmm2,zmm2,zmm29 vpaddd zmm3,zmm3,zmm31 vpaddd zmm0,zmm0,zmm5 vpaddd zmm1,zmm1,zmm6 vpaddd zmm2,zmm2,zmm7 vpaddd zmm3,zmm3,zmm4 vpxord zmm15,zmm15,zmm0 vpxord zmm12,zmm12,zmm1 vpxord zmm13,zmm13,zmm2 vpxord zmm14,zmm14,zmm3 vprord zmm15,zmm15,0x8 vprord zmm12,zmm12,0x8 vprord zmm13,zmm13,0x8 vprord zmm14,zmm14,0x8 vpaddd zmm10,zmm10,zmm15 vpaddd zmm11,zmm11,zmm12 vpaddd zmm8,zmm8,zmm13 vpaddd zmm9,zmm9,zmm14 vpxord zmm5,zmm5,zmm10 vpxord zmm6,zmm6,zmm11 vpxord zmm7,zmm7,zmm8 vpxord zmm4,zmm4,zmm9 vprord zmm5,zmm5,0x7 vprord zmm6,zmm6,0x7 vprord zmm7,zmm7,0x7 vprord zmm4,zmm4,0x7 vpaddd zmm0,zmm0,zmm18 vpaddd zmm1,zmm1,zmm19 vpaddd zmm2,zmm2,zmm23 vpaddd zmm3,zmm3,zmm20 vpaddd zmm0,zmm0,zmm4 vpaddd zmm1,zmm1,zmm5 vpaddd zmm2,zmm2,zmm6 vpaddd zmm3,zmm3,zmm7 vpxord zmm12,zmm12,zmm0 vpxord zmm13,zmm13,zmm1 vpxord zmm14,zmm14,zmm2 vpxord zmm15,zmm15,zmm3 vprord zmm12,zmm12,0x10 vprord zmm13,zmm13,0x10 vprord zmm14,zmm14,0x10 vprord zmm15,zmm15,0x10 vpaddd zmm8,zmm8,zmm12 vpaddd zmm9,zmm9,zmm13 vpaddd zmm10,zmm10,zmm14 vpaddd zmm11,zmm11,zmm15 vpxord zmm4,zmm4,zmm8 vpxord zmm5,zmm5,zmm9 vpxord zmm6,zmm6,zmm10 vpxord zmm7,zmm7,zmm11 vprord zmm4,zmm4,0xc vprord zmm5,zmm5,0xc vprord zmm6,zmm6,0xc vprord zmm7,zmm7,0xc vpaddd zmm0,zmm0,zmm22 vpaddd zmm1,zmm1,zmm26 vpaddd zmm2,zmm2,zmm16 vpaddd zmm3,zmm3,zmm29 vpaddd zmm0,zmm0,zmm4 vpaddd zmm1,zmm1,zmm5 vpaddd zmm2,zmm2,zmm6 vpaddd zmm3,zmm3,zmm7 vpxord zmm12,zmm12,zmm0 vpxord zmm13,zmm13,zmm1 vpxord zmm14,zmm14,zmm2 vpxord zmm15,zmm15,zmm3 vprord zmm12,zmm12,0x8 vprord zmm13,zmm13,0x8 vprord zmm14,zmm14,0x8 vprord zmm15,zmm15,0x8 vpaddd zmm8,zmm8,zmm12 vpaddd zmm9,zmm9,zmm13 vpaddd zmm10,zmm10,zmm14 vpaddd zmm11,zmm11,zmm15 vpxord zmm4,zmm4,zmm8 vpxord zmm5,zmm5,zmm9 vpxord zmm6,zmm6,zmm10 vpxord zmm7,zmm7,zmm11 vprord zmm4,zmm4,0x7 vprord zmm5,zmm5,0x7 vprord zmm6,zmm6,0x7 vprord zmm7,zmm7,0x7 vpaddd zmm0,zmm0,zmm17 vpaddd zmm1,zmm1,zmm28 vpaddd zmm2,zmm2,zmm25 vpaddd zmm3,zmm3,zmm31 vpaddd zmm0,zmm0,zmm5 vpaddd zmm1,zmm1,zmm6 vpaddd zmm2,zmm2,zmm7 vpaddd zmm3,zmm3,zmm4 vpxord zmm15,zmm15,zmm0 vpxord zmm12,zmm12,zmm1 vpxord zmm13,zmm13,zmm2 vpxord zmm14,zmm14,zmm3 vprord zmm15,zmm15,0x10 vprord zmm12,zmm12,0x10 vprord zmm13,zmm13,0x10 vprord zmm14,zmm14,0x10 vpaddd zmm10,zmm10,zmm15 vpaddd zmm11,zmm11,zmm12 vpaddd zmm8,zmm8,zmm13 vpaddd zmm9,zmm9,zmm14 vpxord zmm5,zmm5,zmm10 vpxord zmm6,zmm6,zmm11 vpxord zmm7,zmm7,zmm8 vpxord zmm4,zmm4,zmm9 vprord zmm5,zmm5,0xc vprord zmm6,zmm6,0xc vprord zmm7,zmm7,0xc vprord zmm4,zmm4,0xc vpaddd zmm0,zmm0,zmm27 vpaddd zmm1,zmm1,zmm21 vpaddd zmm2,zmm2,zmm30 vpaddd zmm3,zmm3,zmm24 vpaddd zmm0,zmm0,zmm5 vpaddd zmm1,zmm1,zmm6 vpaddd zmm2,zmm2,zmm7 vpaddd zmm3,zmm3,zmm4 vpxord zmm15,zmm15,zmm0 vpxord zmm12,zmm12,zmm1 vpxord zmm13,zmm13,zmm2 vpxord zmm14,zmm14,zmm3 vprord zmm15,zmm15,0x8 vprord zmm12,zmm12,0x8 vprord zmm13,zmm13,0x8 vprord zmm14,zmm14,0x8 vpaddd zmm10,zmm10,zmm15 vpaddd zmm11,zmm11,zmm12 vpaddd zmm8,zmm8,zmm13 vpaddd zmm9,zmm9,zmm14 vpxord zmm5,zmm5,zmm10 vpxord zmm6,zmm6,zmm11 vpxord zmm7,zmm7,zmm8 vpxord zmm4,zmm4,zmm9 vprord zmm5,zmm5,0x7 vprord zmm6,zmm6,0x7 vprord zmm7,zmm7,0x7 vprord zmm4,zmm4,0x7 vpaddd zmm0,zmm0,zmm19 vpaddd zmm1,zmm1,zmm26 vpaddd zmm2,zmm2,zmm29 vpaddd zmm3,zmm3,zmm23 vpaddd zmm0,zmm0,zmm4 vpaddd zmm1,zmm1,zmm5 vpaddd zmm2,zmm2,zmm6 vpaddd zmm3,zmm3,zmm7 vpxord zmm12,zmm12,zmm0 vpxord zmm13,zmm13,zmm1 vpxord zmm14,zmm14,zmm2 vpxord zmm15,zmm15,zmm3 vprord zmm12,zmm12,0x10 vprord zmm13,zmm13,0x10 vprord zmm14,zmm14,0x10 vprord zmm15,zmm15,0x10 vpaddd zmm8,zmm8,zmm12 vpaddd zmm9,zmm9,zmm13 vpaddd zmm10,zmm10,zmm14 vpaddd zmm11,zmm11,zmm15 vpxord zmm4,zmm4,zmm8 vpxord zmm5,zmm5,zmm9 vpxord zmm6,zmm6,zmm10 vpxord zmm7,zmm7,zmm11 vprord zmm4,zmm4,0xc vprord zmm5,zmm5,0xc vprord zmm6,zmm6,0xc vprord zmm7,zmm7,0xc vpaddd zmm0,zmm0,zmm20 vpaddd zmm1,zmm1,zmm28 vpaddd zmm2,zmm2,zmm18 vpaddd zmm3,zmm3,zmm30 vpaddd zmm0,zmm0,zmm4 vpaddd zmm1,zmm1,zmm5 vpaddd zmm2,zmm2,zmm6 vpaddd zmm3,zmm3,zmm7 vpxord zmm12,zmm12,zmm0 vpxord zmm13,zmm13,zmm1 vpxord zmm14,zmm14,zmm2 vpxord zmm15,zmm15,zmm3 vprord zmm12,zmm12,0x8 vprord zmm13,zmm13,0x8 vprord zmm14,zmm14,0x8 vprord zmm15,zmm15,0x8 vpaddd zmm8,zmm8,zmm12 vpaddd zmm9,zmm9,zmm13 vpaddd zmm10,zmm10,zmm14 vpaddd zmm11,zmm11,zmm15 vpxord zmm4,zmm4,zmm8 vpxord zmm5,zmm5,zmm9 vpxord zmm6,zmm6,zmm10 vpxord zmm7,zmm7,zmm11 vprord zmm4,zmm4,0x7 vprord zmm5,zmm5,0x7 vprord zmm6,zmm6,0x7 vprord zmm7,zmm7,0x7 vpaddd zmm0,zmm0,zmm22 vpaddd zmm1,zmm1,zmm25 vpaddd zmm2,zmm2,zmm27 vpaddd zmm3,zmm3,zmm24 vpaddd zmm0,zmm0,zmm5 vpaddd zmm1,zmm1,zmm6 vpaddd zmm2,zmm2,zmm7 vpaddd zmm3,zmm3,zmm4 vpxord zmm15,zmm15,zmm0 vpxord zmm12,zmm12,zmm1 vpxord zmm13,zmm13,zmm2 vpxord zmm14,zmm14,zmm3 vprord zmm15,zmm15,0x10 vprord zmm12,zmm12,0x10 vprord zmm13,zmm13,0x10 vprord zmm14,zmm14,0x10 vpaddd zmm10,zmm10,zmm15 vpaddd zmm11,zmm11,zmm12 vpaddd zmm8,zmm8,zmm13 vpaddd zmm9,zmm9,zmm14 vpxord zmm5,zmm5,zmm10 vpxord zmm6,zmm6,zmm11 vpxord zmm7,zmm7,zmm8 vpxord zmm4,zmm4,zmm9 vprord zmm5,zmm5,0xc vprord zmm6,zmm6,0xc vprord zmm7,zmm7,0xc vprord zmm4,zmm4,0xc vpaddd zmm0,zmm0,zmm21 vpaddd zmm1,zmm1,zmm16 vpaddd zmm2,zmm2,zmm31 vpaddd zmm3,zmm3,zmm17 vpaddd zmm0,zmm0,zmm5 vpaddd zmm1,zmm1,zmm6 vpaddd zmm2,zmm2,zmm7 vpaddd zmm3,zmm3,zmm4 vpxord zmm15,zmm15,zmm0 vpxord zmm12,zmm12,zmm1 vpxord zmm13,zmm13,zmm2 vpxord zmm14,zmm14,zmm3 vprord zmm15,zmm15,0x8 vprord zmm12,zmm12,0x8 vprord zmm13,zmm13,0x8 vprord zmm14,zmm14,0x8 vpaddd zmm10,zmm10,zmm15 vpaddd zmm11,zmm11,zmm12 vpaddd zmm8,zmm8,zmm13 vpaddd zmm9,zmm9,zmm14 vpxord zmm5,zmm5,zmm10 vpxord zmm6,zmm6,zmm11 vpxord zmm7,zmm7,zmm8 vpxord zmm4,zmm4,zmm9 vprord zmm5,zmm5,0x7 vprord zmm6,zmm6,0x7 vprord zmm7,zmm7,0x7 vprord zmm4,zmm4,0x7 vpaddd zmm0,zmm0,zmm26 vpaddd zmm1,zmm1,zmm28 vpaddd zmm2,zmm2,zmm30 vpaddd zmm3,zmm3,zmm29 vpaddd zmm0,zmm0,zmm4 vpaddd zmm1,zmm1,zmm5 vpaddd zmm2,zmm2,zmm6 vpaddd zmm3,zmm3,zmm7 vpxord zmm12,zmm12,zmm0 vpxord zmm13,zmm13,zmm1 vpxord zmm14,zmm14,zmm2 vpxord zmm15,zmm15,zmm3 vprord zmm12,zmm12,0x10 vprord zmm13,zmm13,0x10 vprord zmm14,zmm14,0x10 vprord zmm15,zmm15,0x10 vpaddd zmm8,zmm8,zmm12 vpaddd zmm9,zmm9,zmm13 vpaddd zmm10,zmm10,zmm14 vpaddd zmm11,zmm11,zmm15 vpxord zmm4,zmm4,zmm8 vpxord zmm5,zmm5,zmm9 vpxord zmm6,zmm6,zmm10 vpxord zmm7,zmm7,zmm11 vprord zmm4,zmm4,0xc vprord zmm5,zmm5,0xc vprord zmm6,zmm6,0xc vprord zmm7,zmm7,0xc vpaddd zmm0,zmm0,zmm23 vpaddd zmm1,zmm1,zmm25 vpaddd zmm2,zmm2,zmm19 vpaddd zmm3,zmm3,zmm31 vpaddd zmm0,zmm0,zmm4 vpaddd zmm1,zmm1,zmm5 vpaddd zmm2,zmm2,zmm6 vpaddd zmm3,zmm3,zmm7 vpxord zmm12,zmm12,zmm0 vpxord zmm13,zmm13,zmm1 vpxord zmm14,zmm14,zmm2 vpxord zmm15,zmm15,zmm3 vprord zmm12,zmm12,0x8 vprord zmm13,zmm13,0x8 vprord zmm14,zmm14,0x8 vprord zmm15,zmm15,0x8 vpaddd zmm8,zmm8,zmm12 vpaddd zmm9,zmm9,zmm13 vpaddd zmm10,zmm10,zmm14 vpaddd zmm11,zmm11,zmm15 vpxord zmm4,zmm4,zmm8 vpxord zmm5,zmm5,zmm9 vpxord zmm6,zmm6,zmm10 vpxord zmm7,zmm7,zmm11 vprord zmm4,zmm4,0x7 vprord zmm5,zmm5,0x7 vprord zmm6,zmm6,0x7 vprord zmm7,zmm7,0x7 vpaddd zmm0,zmm0,zmm20 vpaddd zmm1,zmm1,zmm27 vpaddd zmm2,zmm2,zmm21 vpaddd zmm3,zmm3,zmm17 vpaddd zmm0,zmm0,zmm5 vpaddd zmm1,zmm1,zmm6 vpaddd zmm2,zmm2,zmm7 vpaddd zmm3,zmm3,zmm4 vpxord zmm15,zmm15,zmm0 vpxord zmm12,zmm12,zmm1 vpxord zmm13,zmm13,zmm2 vpxord zmm14,zmm14,zmm3 vprord zmm15,zmm15,0x10 vprord zmm12,zmm12,0x10 vprord zmm13,zmm13,0x10 vprord zmm14,zmm14,0x10 vpaddd zmm10,zmm10,zmm15 vpaddd zmm11,zmm11,zmm12 vpaddd zmm8,zmm8,zmm13 vpaddd zmm9,zmm9,zmm14 vpxord zmm5,zmm5,zmm10 vpxord zmm6,zmm6,zmm11 vpxord zmm7,zmm7,zmm8 vpxord zmm4,zmm4,zmm9 vprord zmm5,zmm5,0xc vprord zmm6,zmm6,0xc vprord zmm7,zmm7,0xc vprord zmm4,zmm4,0xc vpaddd zmm0,zmm0,zmm16 vpaddd zmm1,zmm1,zmm18 vpaddd zmm2,zmm2,zmm24 vpaddd zmm3,zmm3,zmm22 vpaddd zmm0,zmm0,zmm5 vpaddd zmm1,zmm1,zmm6 vpaddd zmm2,zmm2,zmm7 vpaddd zmm3,zmm3,zmm4 vpxord zmm15,zmm15,zmm0 vpxord zmm12,zmm12,zmm1 vpxord zmm13,zmm13,zmm2 vpxord zmm14,zmm14,zmm3 vprord zmm15,zmm15,0x8 vprord zmm12,zmm12,0x8 vprord zmm13,zmm13,0x8 vprord zmm14,zmm14,0x8 vpaddd zmm10,zmm10,zmm15 vpaddd zmm11,zmm11,zmm12 vpaddd zmm8,zmm8,zmm13 vpaddd zmm9,zmm9,zmm14 vpxord zmm5,zmm5,zmm10 vpxord zmm6,zmm6,zmm11 vpxord zmm7,zmm7,zmm8 vpxord zmm4,zmm4,zmm9 vprord zmm5,zmm5,0x7 vprord zmm6,zmm6,0x7 vprord zmm7,zmm7,0x7 vprord zmm4,zmm4,0x7 vpaddd zmm0,zmm0,zmm28 vpaddd zmm1,zmm1,zmm25 vpaddd zmm2,zmm2,zmm31 vpaddd zmm3,zmm3,zmm30 vpaddd zmm0,zmm0,zmm4 vpaddd zmm1,zmm1,zmm5 vpaddd zmm2,zmm2,zmm6 vpaddd zmm3,zmm3,zmm7 vpxord zmm12,zmm12,zmm0 vpxord zmm13,zmm13,zmm1 vpxord zmm14,zmm14,zmm2 vpxord zmm15,zmm15,zmm3 vprord zmm12,zmm12,0x10 vprord zmm13,zmm13,0x10 vprord zmm14,zmm14,0x10 vprord zmm15,zmm15,0x10 vpaddd zmm8,zmm8,zmm12 vpaddd zmm9,zmm9,zmm13 vpaddd zmm10,zmm10,zmm14 vpaddd zmm11,zmm11,zmm15 vpxord zmm4,zmm4,zmm8 vpxord zmm5,zmm5,zmm9 vpxord zmm6,zmm6,zmm10 vpxord zmm7,zmm7,zmm11 vprord zmm4,zmm4,0xc vprord zmm5,zmm5,0xc vprord zmm6,zmm6,0xc vprord zmm7,zmm7,0xc vpaddd zmm0,zmm0,zmm29 vpaddd zmm1,zmm1,zmm27 vpaddd zmm2,zmm2,zmm26 vpaddd zmm3,zmm3,zmm24 vpaddd zmm0,zmm0,zmm4 vpaddd zmm1,zmm1,zmm5 vpaddd zmm2,zmm2,zmm6 vpaddd zmm3,zmm3,zmm7 vpxord zmm12,zmm12,zmm0 vpxord zmm13,zmm13,zmm1 vpxord zmm14,zmm14,zmm2 vpxord zmm15,zmm15,zmm3 vprord zmm12,zmm12,0x8 vprord zmm13,zmm13,0x8 vprord zmm14,zmm14,0x8 vprord zmm15,zmm15,0x8 vpaddd zmm8,zmm8,zmm12 vpaddd zmm9,zmm9,zmm13 vpaddd zmm10,zmm10,zmm14 vpaddd zmm11,zmm11,zmm15 vpxord zmm4,zmm4,zmm8 vpxord zmm5,zmm5,zmm9 vpxord zmm6,zmm6,zmm10 vpxord zmm7,zmm7,zmm11 vprord zmm4,zmm4,0x7 vprord zmm5,zmm5,0x7 vprord zmm6,zmm6,0x7 vprord zmm7,zmm7,0x7 vpaddd zmm0,zmm0,zmm23 vpaddd zmm1,zmm1,zmm21 vpaddd zmm2,zmm2,zmm16 vpaddd zmm3,zmm3,zmm22 vpaddd zmm0,zmm0,zmm5 vpaddd zmm1,zmm1,zmm6 vpaddd zmm2,zmm2,zmm7 vpaddd zmm3,zmm3,zmm4 vpxord zmm15,zmm15,zmm0 vpxord zmm12,zmm12,zmm1 vpxord zmm13,zmm13,zmm2 vpxord zmm14,zmm14,zmm3 vprord zmm15,zmm15,0x10 vprord zmm12,zmm12,0x10 vprord zmm13,zmm13,0x10 vprord zmm14,zmm14,0x10 vpaddd zmm10,zmm10,zmm15 vpaddd zmm11,zmm11,zmm12 vpaddd zmm8,zmm8,zmm13 vpaddd zmm9,zmm9,zmm14 vpxord zmm5,zmm5,zmm10 vpxord zmm6,zmm6,zmm11 vpxord zmm7,zmm7,zmm8 vpxord zmm4,zmm4,zmm9 vprord zmm5,zmm5,0xc vprord zmm6,zmm6,0xc vprord zmm7,zmm7,0xc vprord zmm4,zmm4,0xc vpaddd zmm0,zmm0,zmm18 vpaddd zmm1,zmm1,zmm19 vpaddd zmm2,zmm2,zmm17 vpaddd zmm3,zmm3,zmm20 vpaddd zmm0,zmm0,zmm5 vpaddd zmm1,zmm1,zmm6 vpaddd zmm2,zmm2,zmm7 vpaddd zmm3,zmm3,zmm4 vpxord zmm15,zmm15,zmm0 vpxord zmm12,zmm12,zmm1 vpxord zmm13,zmm13,zmm2 vpxord zmm14,zmm14,zmm3 vprord zmm15,zmm15,0x8 vprord zmm12,zmm12,0x8 vprord zmm13,zmm13,0x8 vprord zmm14,zmm14,0x8 vpaddd zmm10,zmm10,zmm15 vpaddd zmm11,zmm11,zmm12 vpaddd zmm8,zmm8,zmm13 vpaddd zmm9,zmm9,zmm14 vpxord zmm5,zmm5,zmm10 vpxord zmm6,zmm6,zmm11 vpxord zmm7,zmm7,zmm8 vpxord zmm4,zmm4,zmm9 vprord zmm5,zmm5,0x7 vprord zmm6,zmm6,0x7 vprord zmm7,zmm7,0x7 vprord zmm4,zmm4,0x7 vpaddd zmm0,zmm0,zmm25 vpaddd zmm1,zmm1,zmm27 vpaddd zmm2,zmm2,zmm24 vpaddd zmm3,zmm3,zmm31 vpaddd zmm0,zmm0,zmm4 vpaddd zmm1,zmm1,zmm5 vpaddd zmm2,zmm2,zmm6 vpaddd zmm3,zmm3,zmm7 vpxord zmm12,zmm12,zmm0 vpxord zmm13,zmm13,zmm1 vpxord zmm14,zmm14,zmm2 vpxord zmm15,zmm15,zmm3 vprord zmm12,zmm12,0x10 vprord zmm13,zmm13,0x10 vprord zmm14,zmm14,0x10 vprord zmm15,zmm15,0x10 vpaddd zmm8,zmm8,zmm12 vpaddd zmm9,zmm9,zmm13 vpaddd zmm10,zmm10,zmm14 vpaddd zmm11,zmm11,zmm15 vpxord zmm4,zmm4,zmm8 vpxord zmm5,zmm5,zmm9 vpxord zmm6,zmm6,zmm10 vpxord zmm7,zmm7,zmm11 vprord zmm4,zmm4,0xc vprord zmm5,zmm5,0xc vprord zmm6,zmm6,0xc vprord zmm7,zmm7,0xc vpaddd zmm0,zmm0,zmm30 vpaddd zmm1,zmm1,zmm21 vpaddd zmm2,zmm2,zmm28 vpaddd zmm3,zmm3,zmm17 vpaddd zmm0,zmm0,zmm4 vpaddd zmm1,zmm1,zmm5 vpaddd zmm2,zmm2,zmm6 vpaddd zmm3,zmm3,zmm7 vpxord zmm12,zmm12,zmm0 vpxord zmm13,zmm13,zmm1 vpxord zmm14,zmm14,zmm2 vpxord zmm15,zmm15,zmm3 vprord zmm12,zmm12,0x8 vprord zmm13,zmm13,0x8 vprord zmm14,zmm14,0x8 vprord zmm15,zmm15,0x8 vpaddd zmm8,zmm8,zmm12 vpaddd zmm9,zmm9,zmm13 vpaddd zmm10,zmm10,zmm14 vpaddd zmm11,zmm11,zmm15 vpxord zmm4,zmm4,zmm8 vpxord zmm5,zmm5,zmm9 vpxord zmm6,zmm6,zmm10 vpxord zmm7,zmm7,zmm11 vprord zmm4,zmm4,0x7 vprord zmm5,zmm5,0x7 vprord zmm6,zmm6,0x7 vprord zmm7,zmm7,0x7 vpaddd zmm0,zmm0,zmm29 vpaddd zmm1,zmm1,zmm16 vpaddd zmm2,zmm2,zmm18 vpaddd zmm3,zmm3,zmm20 vpaddd zmm0,zmm0,zmm5 vpaddd zmm1,zmm1,zmm6 vpaddd zmm2,zmm2,zmm7 vpaddd zmm3,zmm3,zmm4 vpxord zmm15,zmm15,zmm0 vpxord zmm12,zmm12,zmm1 vpxord zmm13,zmm13,zmm2 vpxord zmm14,zmm14,zmm3 vprord zmm15,zmm15,0x10 vprord zmm12,zmm12,0x10 vprord zmm13,zmm13,0x10 vprord zmm14,zmm14,0x10 vpaddd zmm10,zmm10,zmm15 vpaddd zmm11,zmm11,zmm12 vpaddd zmm8,zmm8,zmm13 vpaddd zmm9,zmm9,zmm14 vpxord zmm5,zmm5,zmm10 vpxord zmm6,zmm6,zmm11 vpxord zmm7,zmm7,zmm8 vpxord zmm4,zmm4,zmm9 vprord zmm5,zmm5,0xc vprord zmm6,zmm6,0xc vprord zmm7,zmm7,0xc vprord zmm4,zmm4,0xc vpaddd zmm0,zmm0,zmm19 vpaddd zmm1,zmm1,zmm26 vpaddd zmm2,zmm2,zmm22 vpaddd zmm3,zmm3,zmm23 vpaddd zmm0,zmm0,zmm5 vpaddd zmm1,zmm1,zmm6 vpaddd zmm2,zmm2,zmm7 vpaddd zmm3,zmm3,zmm4 vpxord zmm15,zmm15,zmm0 vpxord zmm12,zmm12,zmm1 vpxord zmm13,zmm13,zmm2 vpxord zmm14,zmm14,zmm3 vprord zmm15,zmm15,0x8 vprord zmm12,zmm12,0x8 vprord zmm13,zmm13,0x8 vprord zmm14,zmm14,0x8 vpaddd zmm10,zmm10,zmm15 vpaddd zmm11,zmm11,zmm12 vpaddd zmm8,zmm8,zmm13 vpaddd zmm9,zmm9,zmm14 vpxord zmm5,zmm5,zmm10 vpxord zmm6,zmm6,zmm11 vpxord zmm7,zmm7,zmm8 vpxord zmm4,zmm4,zmm9 vprord zmm5,zmm5,0x7 vprord zmm6,zmm6,0x7 vprord zmm7,zmm7,0x7 vprord zmm4,zmm4,0x7 vpaddd zmm0,zmm0,zmm27 vpaddd zmm1,zmm1,zmm21 vpaddd zmm2,zmm2,zmm17 vpaddd zmm3,zmm3,zmm24 vpaddd zmm0,zmm0,zmm4 vpaddd zmm1,zmm1,zmm5 vpaddd zmm2,zmm2,zmm6 vpaddd zmm3,zmm3,zmm7 vpxord zmm12,zmm12,zmm0 vpxord zmm13,zmm13,zmm1 vpxord zmm14,zmm14,zmm2 vpxord zmm15,zmm15,zmm3 vprord zmm12,zmm12,0x10 vprord zmm13,zmm13,0x10 vprord zmm14,zmm14,0x10 vprord zmm15,zmm15,0x10 vpaddd zmm8,zmm8,zmm12 vpaddd zmm9,zmm9,zmm13 vpaddd zmm10,zmm10,zmm14 vpaddd zmm11,zmm11,zmm15 vpxord zmm4,zmm4,zmm8 vpxord zmm5,zmm5,zmm9 vpxord zmm6,zmm6,zmm10 vpxord zmm7,zmm7,zmm11 vprord zmm4,zmm4,0xc vprord zmm5,zmm5,0xc vprord zmm6,zmm6,0xc vprord zmm7,zmm7,0xc vpaddd zmm0,zmm0,zmm31 vpaddd zmm1,zmm1,zmm16 vpaddd zmm2,zmm2,zmm25 vpaddd zmm3,zmm3,zmm22 vpaddd zmm0,zmm0,zmm4 vpaddd zmm1,zmm1,zmm5 vpaddd zmm2,zmm2,zmm6 vpaddd zmm3,zmm3,zmm7 vpxord zmm12,zmm12,zmm0 vpxord zmm13,zmm13,zmm1 vpxord zmm14,zmm14,zmm2 vpxord zmm15,zmm15,zmm3 vprord zmm12,zmm12,0x8 vprord zmm13,zmm13,0x8 vprord zmm14,zmm14,0x8 vprord zmm15,zmm15,0x8 vpaddd zmm8,zmm8,zmm12 vpaddd zmm9,zmm9,zmm13 vpaddd zmm10,zmm10,zmm14 vpaddd zmm11,zmm11,zmm15 vpxord zmm4,zmm4,zmm8 vpxord zmm5,zmm5,zmm9 vpxord zmm6,zmm6,zmm10 vpxord zmm7,zmm7,zmm11 vprord zmm4,zmm4,0x7 vprord zmm5,zmm5,0x7 vprord zmm6,zmm6,0x7 vprord zmm7,zmm7,0x7 vpaddd zmm0,zmm0,zmm30 vpaddd zmm1,zmm1,zmm18 vpaddd zmm2,zmm2,zmm19 vpaddd zmm3,zmm3,zmm23 vpaddd zmm0,zmm0,zmm5 vpaddd zmm1,zmm1,zmm6 vpaddd zmm2,zmm2,zmm7 vpaddd zmm3,zmm3,zmm4 vpxord zmm15,zmm15,zmm0 vpxord zmm12,zmm12,zmm1 vpxord zmm13,zmm13,zmm2 vpxord zmm14,zmm14,zmm3 vprord zmm15,zmm15,0x10 vprord zmm12,zmm12,0x10 vprord zmm13,zmm13,0x10 vprord zmm14,zmm14,0x10 vpaddd zmm10,zmm10,zmm15 vpaddd zmm11,zmm11,zmm12 vpaddd zmm8,zmm8,zmm13 vpaddd zmm9,zmm9,zmm14 vpxord zmm5,zmm5,zmm10 vpxord zmm6,zmm6,zmm11 vpxord zmm7,zmm7,zmm8 vpxord zmm4,zmm4,zmm9 vprord zmm5,zmm5,0xc vprord zmm6,zmm6,0xc vprord zmm7,zmm7,0xc vprord zmm4,zmm4,0xc vpaddd zmm0,zmm0,zmm26 vpaddd zmm1,zmm1,zmm28 vpaddd zmm2,zmm2,zmm20 vpaddd zmm3,zmm3,zmm29 vpaddd zmm0,zmm0,zmm5 vpaddd zmm1,zmm1,zmm6 vpaddd zmm2,zmm2,zmm7 vpaddd zmm3,zmm3,zmm4 vpxord zmm15,zmm15,zmm0 vpxord zmm12,zmm12,zmm1 vpxord zmm13,zmm13,zmm2 vpxord zmm14,zmm14,zmm3 vprord zmm15,zmm15,0x8 vprord zmm12,zmm12,0x8 vprord zmm13,zmm13,0x8 vprord zmm14,zmm14,0x8 vpaddd zmm10,zmm10,zmm15 vpaddd zmm11,zmm11,zmm12 vpaddd zmm8,zmm8,zmm13 vpaddd zmm9,zmm9,zmm14 vpxord zmm5,zmm5,zmm10 vpxord zmm6,zmm6,zmm11 vpxord zmm7,zmm7,zmm8 vpxord zmm4,zmm4,zmm9 vprord zmm5,zmm5,0x7 vprord zmm6,zmm6,0x7 vprord zmm7,zmm7,0x7 vprord zmm4,zmm4,0x7 vpxord zmm0,zmm0,zmm8 vpxord zmm1,zmm1,zmm9 vpxord zmm2,zmm2,zmm10 vpxord zmm3,zmm3,zmm11 vpxord zmm4,zmm4,zmm12 vpxord zmm5,zmm5,zmm13 vpxord zmm6,zmm6,zmm14 vpxord zmm7,zmm7,zmm15 vpxord zmm8,zmm8,DWORD PTR [rdi]{1to16} vpxord zmm9,zmm9,DWORD PTR [rdi+0x4]{1to16} vpxord zmm10,zmm10,DWORD PTR [rdi+0x8]{1to16} vpxord zmm11,zmm11,DWORD PTR [rdi+0xc]{1to16} vpxord zmm12,zmm12,DWORD PTR [rdi+0x10]{1to16} vpxord zmm13,zmm13,DWORD PTR [rdi+0x14]{1to16} vpxord zmm14,zmm14,DWORD PTR [rdi+0x18]{1to16} vpxord zmm15,zmm15,DWORD PTR [rdi+0x1c]{1to16} vpunpckldq zmm16,zmm0,zmm1 vpunpckhdq zmm17,zmm0,zmm1 vpunpckldq zmm18,zmm2,zmm3 vpunpckhdq zmm19,zmm2,zmm3 vpunpckldq zmm20,zmm4,zmm5 vpunpckhdq zmm21,zmm4,zmm5 vpunpckldq zmm22,zmm6,zmm7 vpunpckhdq zmm23,zmm6,zmm7 vpunpckldq zmm24,zmm8,zmm9 vpunpckhdq zmm25,zmm8,zmm9 vpunpckldq zmm26,zmm10,zmm11 vpunpckhdq zmm27,zmm10,zmm11 vpunpckldq zmm28,zmm12,zmm13 vpunpckhdq zmm29,zmm12,zmm13 vpunpckldq zmm30,zmm14,zmm15 vpunpckhdq zmm31,zmm14,zmm15 vpunpcklqdq zmm0,zmm16,zmm18 vpunpckhqdq zmm1,zmm16,zmm18 vpunpcklqdq zmm2,zmm17,zmm19 vpunpckhqdq zmm3,zmm17,zmm19 vpunpcklqdq zmm4,zmm20,zmm22 vpunpckhqdq zmm5,zmm20,zmm22 vpunpcklqdq zmm6,zmm21,zmm23 vpunpckhqdq zmm7,zmm21,zmm23 vpunpcklqdq zmm8,zmm24,zmm26 vpunpckhqdq zmm9,zmm24,zmm26 vpunpcklqdq zmm10,zmm25,zmm27 vpunpckhqdq zmm11,zmm25,zmm27 vpunpcklqdq zmm12,zmm28,zmm30 vpunpckhqdq zmm13,zmm28,zmm30 vpunpcklqdq zmm14,zmm29,zmm31 vpunpckhqdq zmm15,zmm29,zmm31 vshufi32x4 zmm16,zmm0,zmm4,0x88 vshufi32x4 zmm17,zmm1,zmm5,0x88 vshufi32x4 zmm18,zmm2,zmm6,0x88 vshufi32x4 zmm19,zmm3,zmm7,0x88 vshufi32x4 zmm20,zmm0,zmm4,0xdd vshufi32x4 zmm21,zmm1,zmm5,0xdd vshufi32x4 zmm22,zmm2,zmm6,0xdd vshufi32x4 zmm23,zmm3,zmm7,0xdd vshufi32x4 zmm24,zmm8,zmm12,0x88 vshufi32x4 zmm25,zmm9,zmm13,0x88 vshufi32x4 zmm26,zmm10,zmm14,0x88 vshufi32x4 zmm27,zmm11,zmm15,0x88 vshufi32x4 zmm28,zmm8,zmm12,0xdd vshufi32x4 zmm29,zmm9,zmm13,0xdd vshufi32x4 zmm30,zmm10,zmm14,0xdd vshufi32x4 zmm31,zmm11,zmm15,0xdd vshufi32x4 zmm0,zmm16,zmm24,0x88 vshufi32x4 zmm1,zmm17,zmm25,0x88 vshufi32x4 zmm2,zmm18,zmm26,0x88 vshufi32x4 zmm3,zmm19,zmm27,0x88 vshufi32x4 zmm4,zmm20,zmm28,0x88 vshufi32x4 zmm5,zmm21,zmm29,0x88 vshufi32x4 zmm6,zmm22,zmm30,0x88 vshufi32x4 zmm7,zmm23,zmm31,0x88 vshufi32x4 zmm8,zmm16,zmm24,0xdd vshufi32x4 zmm9,zmm17,zmm25,0xdd vshufi32x4 zmm10,zmm18,zmm26,0xdd vshufi32x4 zmm11,zmm19,zmm27,0xdd vshufi32x4 zmm12,zmm20,zmm28,0xdd vshufi32x4 zmm13,zmm21,zmm29,0xdd vshufi32x4 zmm14,zmm22,zmm30,0xdd vshufi32x4 zmm15,zmm23,zmm31,0xdd vmovdqu32 ZMMWORD PTR [r9],zmm0 vmovdqu32 ZMMWORD PTR [r9+0x40],zmm1 vmovdqu32 ZMMWORD PTR [r9+0x80],zmm2 vmovdqu32 ZMMWORD PTR [r9+0xc0],zmm3 vmovdqu32 ZMMWORD PTR [r9+0x100],zmm4 vmovdqu32 ZMMWORD PTR [r9+0x140],zmm5 vmovdqu32 ZMMWORD PTR [r9+0x180],zmm6 vmovdqu32 ZMMWORD PTR [r9+0x1c0],zmm7 vmovdqu32 ZMMWORD PTR [r9+0x200],zmm8 vmovdqu32 ZMMWORD PTR [r9+0x240],zmm9 vmovdqu32 ZMMWORD PTR [r9+0x280],zmm10 vmovdqu32 ZMMWORD PTR [r9+0x2c0],zmm11 vmovdqu32 ZMMWORD PTR [r9+0x300],zmm12 vmovdqu32 ZMMWORD PTR [r9+0x340],zmm13 vmovdqu32 ZMMWORD PTR [r9+0x380],zmm14 vmovdqu32 ZMMWORD PTR [r9+0x3c0],zmm15 vmovdqa32 zmm0,ZMMWORD PTR [rsp] vmovdqa32 zmm1,ZMMWORD PTR [rsp+0x40] vpaddd zmm2,zmm0,DWORD PTR [ADD16+rip]{1to16} vpcmpltud k1,zmm2,zmm0 vpaddd zmm1{k1},zmm1,DWORD PTR [ADD1+rip]{1to16} vmovdqa32 ZMMWORD PTR [rsp],zmm2 vmovdqa32 ZMMWORD PTR [rsp+0x40],zmm1 add r9,0x400 sub r10,0x10 cmp r10,0x10 jae 3b test r10,r10 jne 2f 9: vzeroupper mov rsp,rbp pop rbp ret 2: test r10,0x8 je 2f vpbroadcastd ymm16,DWORD PTR [rsi] vpbroadcastd ymm17,DWORD PTR [rsi+0x4] vpbroadcastd ymm18,DWORD PTR [rsi+0x8] vpbroadcastd ymm19,DWORD PTR [rsi+0xc] vpbroadcastd ymm20,DWORD PTR [rsi+0x10] vpbroadcastd ymm21,DWORD PTR [rsi+0x14] vpbroadcastd ymm22,DWORD PTR [rsi+0x18] vpbroadcastd ymm23,DWORD PTR [rsi+0x1c] vpbroadcastd ymm24,DWORD PTR [rsi+0x20] vpbroadcastd ymm25,DWORD PTR [rsi+0x24] vpbroadcastd ymm26,DWORD PTR [rsi+0x28] vpbroadcastd ymm27,DWORD PTR [rsi+0x2c] vpbroadcastd ymm28,DWORD PTR [rsi+0x30] vpbroadcastd ymm29,DWORD PTR [rsi+0x34] vpbroadcastd ymm30,DWORD PTR [rsi+0x38] vpbroadcastd ymm31,DWORD PTR [rsi+0x3c] vpbroadcastd ymm0,DWORD PTR [rdi] vpbroadcastd ymm1,DWORD PTR [rdi+0x4] vpbroadcastd ymm2,DWORD PTR [rdi+0x8] vpbroadcastd ymm3,DWORD PTR [rdi+0xc] vpbroadcastd ymm4,DWORD PTR [rdi+0x10] vpbroadcastd ymm5,DWORD PTR [rdi+0x14] vpbroadcastd ymm6,DWORD PTR [rdi+0x18] vpbroadcastd ymm7,DWORD PTR [rdi+0x1c] vpbroadcastd ymm8,DWORD PTR [BLAKE3_IV_0+rip] vpbroadcastd ymm9,DWORD PTR [BLAKE3_IV_1+rip] vpbroadcastd ymm10,DWORD PTR [BLAKE3_IV_2+rip] vpbroadcastd ymm11,DWORD PTR [BLAKE3_IV_3+rip] vmovdqa ymm12,YMMWORD PTR [rsp] vmovdqa ymm13,YMMWORD PTR [rsp+0x40] vpbroadcastd ymm14,edx vpbroadcastd ymm15,r8d vpaddd ymm0,ymm0,ymm16 vpaddd ymm1,ymm1,ymm18 vpaddd ymm2,ymm2,ymm20 vpaddd ymm3,ymm3,ymm22 vpaddd ymm0,ymm0,ymm4 vpaddd ymm1,ymm1,ymm5 vpaddd ymm2,ymm2,ymm6 vpaddd ymm3,ymm3,ymm7 vpxord ymm12,ymm12,ymm0 vpxord ymm13,ymm13,ymm1 vpxord ymm14,ymm14,ymm2 vpxord ymm15,ymm15,ymm3 vprord ymm12,ymm12,0x10 vprord ymm13,ymm13,0x10 vprord ymm14,ymm14,0x10 vprord ymm15,ymm15,0x10 vpaddd ymm8,ymm8,ymm12 vpaddd ymm9,ymm9,ymm13 vpaddd ymm10,ymm10,ymm14 vpaddd ymm11,ymm11,ymm15 vpxord ymm4,ymm4,ymm8 vpxord ymm5,ymm5,ymm9 vpxord ymm6,ymm6,ymm10 vpxord ymm7,ymm7,ymm11 vprord ymm4,ymm4,0xc vprord ymm5,ymm5,0xc vprord ymm6,ymm6,0xc vprord ymm7,ymm7,0xc vpaddd ymm0,ymm0,ymm17 vpaddd ymm1,ymm1,ymm19 vpaddd ymm2,ymm2,ymm21 vpaddd ymm3,ymm3,ymm23 vpaddd ymm0,ymm0,ymm4 vpaddd ymm1,ymm1,ymm5 vpaddd ymm2,ymm2,ymm6 vpaddd ymm3,ymm3,ymm7 vpxord ymm12,ymm12,ymm0 vpxord ymm13,ymm13,ymm1 vpxord ymm14,ymm14,ymm2 vpxord ymm15,ymm15,ymm3 vprord ymm12,ymm12,0x8 vprord ymm13,ymm13,0x8 vprord ymm14,ymm14,0x8 vprord ymm15,ymm15,0x8 vpaddd ymm8,ymm8,ymm12 vpaddd ymm9,ymm9,ymm13 vpaddd ymm10,ymm10,ymm14 vpaddd ymm11,ymm11,ymm15 vpxord ymm4,ymm4,ymm8 vpxord ymm5,ymm5,ymm9 vpxord ymm6,ymm6,ymm10 vpxord ymm7,ymm7,ymm11 vprord ymm4,ymm4,0x7 vprord ymm5,ymm5,0x7 vprord ymm6,ymm6,0x7 vprord ymm7,ymm7,0x7 vpaddd ymm0,ymm0,ymm24 vpaddd ymm1,ymm1,ymm26 vpaddd ymm2,ymm2,ymm28 vpaddd ymm3,ymm3,ymm30 vpaddd ymm0,ymm0,ymm5 vpaddd ymm1,ymm1,ymm6 vpaddd ymm2,ymm2,ymm7 vpaddd ymm3,ymm3,ymm4 vpxord ymm15,ymm15,ymm0 vpxord ymm12,ymm12,ymm1 vpxord ymm13,ymm13,ymm2 vpxord ymm14,ymm14,ymm3 vprord ymm15,ymm15,0x10 vprord ymm12,ymm12,0x10 vprord ymm13,ymm13,0x10 vprord ymm14,ymm14,0x10 vpaddd ymm10,ymm10,ymm15 vpaddd ymm11,ymm11,ymm12 vpaddd ymm8,ymm8,ymm13 vpaddd ymm9,ymm9,ymm14 vpxord ymm5,ymm5,ymm10 vpxord ymm6,ymm6,ymm11 vpxord ymm7,ymm7,ymm8 vpxord ymm4,ymm4,ymm9 vprord ymm5,ymm5,0xc vprord ymm6,ymm6,0xc vprord ymm7,ymm7,0xc vprord ymm4,ymm4,0xc vpaddd ymm0,ymm0,ymm25 vpaddd ymm1,ymm1,ymm27 vpaddd ymm2,ymm2,ymm29 vpaddd ymm3,ymm3,ymm31 vpaddd ymm0,ymm0,ymm5 vpaddd ymm1,ymm1,ymm6 vpaddd ymm2,ymm2,ymm7 vpaddd ymm3,ymm3,ymm4 vpxord ymm15,ymm15,ymm0 vpxord ymm12,ymm12,ymm1 vpxord ymm13,ymm13,ymm2 vpxord ymm14,ymm14,ymm3 vprord ymm15,ymm15,0x8 vprord ymm12,ymm12,0x8 vprord ymm13,ymm13,0x8 vprord ymm14,ymm14,0x8 vpaddd ymm10,ymm10,ymm15 vpaddd ymm11,ymm11,ymm12 vpaddd ymm8,ymm8,ymm13 vpaddd ymm9,ymm9,ymm14 vpxord ymm5,ymm5,ymm10 vpxord ymm6,ymm6,ymm11 vpxord ymm7,ymm7,ymm8 vpxord ymm4,ymm4,ymm9 vprord ymm5,ymm5,0x7 vprord ymm6,ymm6,0x7 vprord ymm7,ymm7,0x7 vprord ymm4,ymm4,0x7 vpaddd ymm0,ymm0,ymm18 vpaddd ymm1,ymm1,ymm19 vpaddd ymm2,ymm2,ymm23 vpaddd ymm3,ymm3,ymm20 vpaddd ymm0,ymm0,ymm4 vpaddd ymm1,ymm1,ymm5 vpaddd ymm2,ymm2,ymm6 vpaddd ymm3,ymm3,ymm7 vpxord ymm12,ymm12,ymm0 vpxord ymm13,ymm13,ymm1 vpxord ymm14,ymm14,ymm2 vpxord ymm15,ymm15,ymm3 vprord ymm12,ymm12,0x10 vprord ymm13,ymm13,0x10 vprord ymm14,ymm14,0x10 vprord ymm15,ymm15,0x10 vpaddd ymm8,ymm8,ymm12 vpaddd ymm9,ymm9,ymm13 vpaddd ymm10,ymm10,ymm14 vpaddd ymm11,ymm11,ymm15 vpxord ymm4,ymm4,ymm8 vpxord ymm5,ymm5,ymm9 vpxord ymm6,ymm6,ymm10 vpxord ymm7,ymm7,ymm11 vprord ymm4,ymm4,0xc vprord ymm5,ymm5,0xc vprord ymm6,ymm6,0xc vprord ymm7,ymm7,0xc vpaddd ymm0,ymm0,ymm22 vpaddd ymm1,ymm1,ymm26 vpaddd ymm2,ymm2,ymm16 vpaddd ymm3,ymm3,ymm29 vpaddd ymm0,ymm0,ymm4 vpaddd ymm1,ymm1,ymm5 vpaddd ymm2,ymm2,ymm6 vpaddd ymm3,ymm3,ymm7 vpxord ymm12,ymm12,ymm0 vpxord ymm13,ymm13,ymm1 vpxord ymm14,ymm14,ymm2 vpxord ymm15,ymm15,ymm3 vprord ymm12,ymm12,0x8 vprord ymm13,ymm13,0x8 vprord ymm14,ymm14,0x8 vprord ymm15,ymm15,0x8 vpaddd ymm8,ymm8,ymm12 vpaddd ymm9,ymm9,ymm13 vpaddd ymm10,ymm10,ymm14 vpaddd ymm11,ymm11,ymm15 vpxord ymm4,ymm4,ymm8 vpxord ymm5,ymm5,ymm9 vpxord ymm6,ymm6,ymm10 vpxord ymm7,ymm7,ymm11 vprord ymm4,ymm4,0x7 vprord ymm5,ymm5,0x7 vprord ymm6,ymm6,0x7 vprord ymm7,ymm7,0x7 vpaddd ymm0,ymm0,ymm17 vpaddd ymm1,ymm1,ymm28 vpaddd ymm2,ymm2,ymm25 vpaddd ymm3,ymm3,ymm31 vpaddd ymm0,ymm0,ymm5 vpaddd ymm1,ymm1,ymm6 vpaddd ymm2,ymm2,ymm7 vpaddd ymm3,ymm3,ymm4 vpxord ymm15,ymm15,ymm0 vpxord ymm12,ymm12,ymm1 vpxord ymm13,ymm13,ymm2 vpxord ymm14,ymm14,ymm3 vprord ymm15,ymm15,0x10 vprord ymm12,ymm12,0x10 vprord ymm13,ymm13,0x10 vprord ymm14,ymm14,0x10 vpaddd ymm10,ymm10,ymm15 vpaddd ymm11,ymm11,ymm12 vpaddd ymm8,ymm8,ymm13 vpaddd ymm9,ymm9,ymm14 vpxord ymm5,ymm5,ymm10 vpxord ymm6,ymm6,ymm11 vpxord ymm7,ymm7,ymm8 vpxord ymm4,ymm4,ymm9 vprord ymm5,ymm5,0xc vprord ymm6,ymm6,0xc vprord ymm7,ymm7,0xc vprord ymm4,ymm4,0xc vpaddd ymm0,ymm0,ymm27 vpaddd ymm1,ymm1,ymm21 vpaddd ymm2,ymm2,ymm30 vpaddd ymm3,ymm3,ymm24 vpaddd ymm0,ymm0,ymm5 vpaddd ymm1,ymm1,ymm6 vpaddd ymm2,ymm2,ymm7 vpaddd ymm3,ymm3,ymm4 vpxord ymm15,ymm15,ymm0 vpxord ymm12,ymm12,ymm1 vpxord ymm13,ymm13,ymm2 vpxord ymm14,ymm14,ymm3 vprord ymm15,ymm15,0x8 vprord ymm12,ymm12,0x8 vprord ymm13,ymm13,0x8 vprord ymm14,ymm14,0x8 vpaddd ymm10,ymm10,ymm15 vpaddd ymm11,ymm11,ymm12 vpaddd ymm8,ymm8,ymm13 vpaddd ymm9,ymm9,ymm14 vpxord ymm5,ymm5,ymm10 vpxord ymm6,ymm6,ymm11 vpxord ymm7,ymm7,ymm8 vpxord ymm4,ymm4,ymm9 vprord ymm5,ymm5,0x7 vprord ymm6,ymm6,0x7 vprord ymm7,ymm7,0x7 vprord ymm4,ymm4,0x7 vpaddd ymm0,ymm0,ymm19 vpaddd ymm1,ymm1,ymm26 vpaddd ymm2,ymm2,ymm29 vpaddd ymm3,ymm3,ymm23 vpaddd ymm0,ymm0,ymm4 vpaddd ymm1,ymm1,ymm5 vpaddd ymm2,ymm2,ymm6 vpaddd ymm3,ymm3,ymm7 vpxord ymm12,ymm12,ymm0 vpxord ymm13,ymm13,ymm1 vpxord ymm14,ymm14,ymm2 vpxord ymm15,ymm15,ymm3 vprord ymm12,ymm12,0x10 vprord ymm13,ymm13,0x10 vprord ymm14,ymm14,0x10 vprord ymm15,ymm15,0x10 vpaddd ymm8,ymm8,ymm12 vpaddd ymm9,ymm9,ymm13 vpaddd ymm10,ymm10,ymm14 vpaddd ymm11,ymm11,ymm15 vpxord ymm4,ymm4,ymm8 vpxord ymm5,ymm5,ymm9 vpxord ymm6,ymm6,ymm10 vpxord ymm7,ymm7,ymm11 vprord ymm4,ymm4,0xc vprord ymm5,ymm5,0xc vprord ymm6,ymm6,0xc vprord ymm7,ymm7,0xc vpaddd ymm0,ymm0,ymm20 vpaddd ymm1,ymm1,ymm28 vpaddd ymm2,ymm2,ymm18 vpaddd ymm3,ymm3,ymm30 vpaddd ymm0,ymm0,ymm4 vpaddd ymm1,ymm1,ymm5 vpaddd ymm2,ymm2,ymm6 vpaddd ymm3,ymm3,ymm7 vpxord ymm12,ymm12,ymm0 vpxord ymm13,ymm13,ymm1 vpxord ymm14,ymm14,ymm2 vpxord ymm15,ymm15,ymm3 vprord ymm12,ymm12,0x8 vprord ymm13,ymm13,0x8 vprord ymm14,ymm14,0x8 vprord ymm15,ymm15,0x8 vpaddd ymm8,ymm8,ymm12 vpaddd ymm9,ymm9,ymm13 vpaddd ymm10,ymm10,ymm14 vpaddd ymm11,ymm11,ymm15 vpxord ymm4,ymm4,ymm8 vpxord ymm5,ymm5,ymm9 vpxord ymm6,ymm6,ymm10 vpxord ymm7,ymm7,ymm11 vprord ymm4,ymm4,0x7 vprord ymm5,ymm5,0x7 vprord ymm6,ymm6,0x7 vprord ymm7,ymm7,0x7 vpaddd ymm0,ymm0,ymm22 vpaddd ymm1,ymm1,ymm25 vpaddd ymm2,ymm2,ymm27 vpaddd ymm3,ymm3,ymm24 vpaddd ymm0,ymm0,ymm5 vpaddd ymm1,ymm1,ymm6 vpaddd ymm2,ymm2,ymm7 vpaddd ymm3,ymm3,ymm4 vpxord ymm15,ymm15,ymm0 vpxord ymm12,ymm12,ymm1 vpxord ymm13,ymm13,ymm2 vpxord ymm14,ymm14,ymm3 vprord ymm15,ymm15,0x10 vprord ymm12,ymm12,0x10 vprord ymm13,ymm13,0x10 vprord ymm14,ymm14,0x10 vpaddd ymm10,ymm10,ymm15 vpaddd ymm11,ymm11,ymm12 vpaddd ymm8,ymm8,ymm13 vpaddd ymm9,ymm9,ymm14 vpxord ymm5,ymm5,ymm10 vpxord ymm6,ymm6,ymm11 vpxord ymm7,ymm7,ymm8 vpxord ymm4,ymm4,ymm9 vprord ymm5,ymm5,0xc vprord ymm6,ymm6,0xc vprord ymm7,ymm7,0xc vprord ymm4,ymm4,0xc vpaddd ymm0,ymm0,ymm21 vpaddd ymm1,ymm1,ymm16 vpaddd ymm2,ymm2,ymm31 vpaddd ymm3,ymm3,ymm17 vpaddd ymm0,ymm0,ymm5 vpaddd ymm1,ymm1,ymm6 vpaddd ymm2,ymm2,ymm7 vpaddd ymm3,ymm3,ymm4 vpxord ymm15,ymm15,ymm0 vpxord ymm12,ymm12,ymm1 vpxord ymm13,ymm13,ymm2 vpxord ymm14,ymm14,ymm3 vprord ymm15,ymm15,0x8 vprord ymm12,ymm12,0x8 vprord ymm13,ymm13,0x8 vprord ymm14,ymm14,0x8 vpaddd ymm10,ymm10,ymm15 vpaddd ymm11,ymm11,ymm12 vpaddd ymm8,ymm8,ymm13 vpaddd ymm9,ymm9,ymm14 vpxord ymm5,ymm5,ymm10 vpxord ymm6,ymm6,ymm11 vpxord ymm7,ymm7,ymm8 vpxord ymm4,ymm4,ymm9 vprord ymm5,ymm5,0x7 vprord ymm6,ymm6,0x7 vprord ymm7,ymm7,0x7 vprord ymm4,ymm4,0x7 vpaddd ymm0,ymm0,ymm26 vpaddd ymm1,ymm1,ymm28 vpaddd ymm2,ymm2,ymm30 vpaddd ymm3,ymm3,ymm29 vpaddd ymm0,ymm0,ymm4 vpaddd ymm1,ymm1,ymm5 vpaddd ymm2,ymm2,ymm6 vpaddd ymm3,ymm3,ymm7 vpxord ymm12,ymm12,ymm0 vpxord ymm13,ymm13,ymm1 vpxord ymm14,ymm14,ymm2 vpxord ymm15,ymm15,ymm3 vprord ymm12,ymm12,0x10 vprord ymm13,ymm13,0x10 vprord ymm14,ymm14,0x10 vprord ymm15,ymm15,0x10 vpaddd ymm8,ymm8,ymm12 vpaddd ymm9,ymm9,ymm13 vpaddd ymm10,ymm10,ymm14 vpaddd ymm11,ymm11,ymm15 vpxord ymm4,ymm4,ymm8 vpxord ymm5,ymm5,ymm9 vpxord ymm6,ymm6,ymm10 vpxord ymm7,ymm7,ymm11 vprord ymm4,ymm4,0xc vprord ymm5,ymm5,0xc vprord ymm6,ymm6,0xc vprord ymm7,ymm7,0xc vpaddd ymm0,ymm0,ymm23 vpaddd ymm1,ymm1,ymm25 vpaddd ymm2,ymm2,ymm19 vpaddd ymm3,ymm3,ymm31 vpaddd ymm0,ymm0,ymm4 vpaddd ymm1,ymm1,ymm5 vpaddd ymm2,ymm2,ymm6 vpaddd ymm3,ymm3,ymm7 vpxord ymm12,ymm12,ymm0 vpxord ymm13,ymm13,ymm1 vpxord ymm14,ymm14,ymm2 vpxord ymm15,ymm15,ymm3 vprord ymm12,ymm12,0x8 vprord ymm13,ymm13,0x8 vprord ymm14,ymm14,0x8 vprord ymm15,ymm15,0x8 vpaddd ymm8,ymm8,ymm12 vpaddd ymm9,ymm9,ymm13 vpaddd ymm10,ymm10,ymm14 vpaddd ymm11,ymm11,ymm15 vpxord ymm4,ymm4,ymm8 vpxord ymm5,ymm5,ymm9 vpxord ymm6,ymm6,ymm10 vpxord ymm7,ymm7,ymm11 vprord ymm4,ymm4,0x7 vprord ymm5,ymm5,0x7 vprord ymm6,ymm6,0x7 vprord ymm7,ymm7,0x7 vpaddd ymm0,ymm0,ymm20 vpaddd ymm1,ymm1,ymm27 vpaddd ymm2,ymm2,ymm21 vpaddd ymm3,ymm3,ymm17 vpaddd ymm0,ymm0,ymm5 vpaddd ymm1,ymm1,ymm6 vpaddd ymm2,ymm2,ymm7 vpaddd ymm3,ymm3,ymm4 vpxord ymm15,ymm15,ymm0 vpxord ymm12,ymm12,ymm1 vpxord ymm13,ymm13,ymm2 vpxord ymm14,ymm14,ymm3 vprord ymm15,ymm15,0x10 vprord ymm12,ymm12,0x10 vprord ymm13,ymm13,0x10 vprord ymm14,ymm14,0x10 vpaddd ymm10,ymm10,ymm15 vpaddd ymm11,ymm11,ymm12 vpaddd ymm8,ymm8,ymm13 vpaddd ymm9,ymm9,ymm14 vpxord ymm5,ymm5,ymm10 vpxord ymm6,ymm6,ymm11 vpxord ymm7,ymm7,ymm8 vpxord ymm4,ymm4,ymm9 vprord ymm5,ymm5,0xc vprord ymm6,ymm6,0xc vprord ymm7,ymm7,0xc vprord ymm4,ymm4,0xc vpaddd ymm0,ymm0,ymm16 vpaddd ymm1,ymm1,ymm18 vpaddd ymm2,ymm2,ymm24 vpaddd ymm3,ymm3,ymm22 vpaddd ymm0,ymm0,ymm5 vpaddd ymm1,ymm1,ymm6 vpaddd ymm2,ymm2,ymm7 vpaddd ymm3,ymm3,ymm4 vpxord ymm15,ymm15,ymm0 vpxord ymm12,ymm12,ymm1 vpxord ymm13,ymm13,ymm2 vpxord ymm14,ymm14,ymm3 vprord ymm15,ymm15,0x8 vprord ymm12,ymm12,0x8 vprord ymm13,ymm13,0x8 vprord ymm14,ymm14,0x8 vpaddd ymm10,ymm10,ymm15 vpaddd ymm11,ymm11,ymm12 vpaddd ymm8,ymm8,ymm13 vpaddd ymm9,ymm9,ymm14 vpxord ymm5,ymm5,ymm10 vpxord ymm6,ymm6,ymm11 vpxord ymm7,ymm7,ymm8 vpxord ymm4,ymm4,ymm9 vprord ymm5,ymm5,0x7 vprord ymm6,ymm6,0x7 vprord ymm7,ymm7,0x7 vprord ymm4,ymm4,0x7 vpaddd ymm0,ymm0,ymm28 vpaddd ymm1,ymm1,ymm25 vpaddd ymm2,ymm2,ymm31 vpaddd ymm3,ymm3,ymm30 vpaddd ymm0,ymm0,ymm4 vpaddd ymm1,ymm1,ymm5 vpaddd ymm2,ymm2,ymm6 vpaddd ymm3,ymm3,ymm7 vpxord ymm12,ymm12,ymm0 vpxord ymm13,ymm13,ymm1 vpxord ymm14,ymm14,ymm2 vpxord ymm15,ymm15,ymm3 vprord ymm12,ymm12,0x10 vprord ymm13,ymm13,0x10 vprord ymm14,ymm14,0x10 vprord ymm15,ymm15,0x10 vpaddd ymm8,ymm8,ymm12 vpaddd ymm9,ymm9,ymm13 vpaddd ymm10,ymm10,ymm14 vpaddd ymm11,ymm11,ymm15 vpxord ymm4,ymm4,ymm8 vpxord ymm5,ymm5,ymm9 vpxord ymm6,ymm6,ymm10 vpxord ymm7,ymm7,ymm11 vprord ymm4,ymm4,0xc vprord ymm5,ymm5,0xc vprord ymm6,ymm6,0xc vprord ymm7,ymm7,0xc vpaddd ymm0,ymm0,ymm29 vpaddd ymm1,ymm1,ymm27 vpaddd ymm2,ymm2,ymm26 vpaddd ymm3,ymm3,ymm24 vpaddd ymm0,ymm0,ymm4 vpaddd ymm1,ymm1,ymm5 vpaddd ymm2,ymm2,ymm6 vpaddd ymm3,ymm3,ymm7 vpxord ymm12,ymm12,ymm0 vpxord ymm13,ymm13,ymm1 vpxord ymm14,ymm14,ymm2 vpxord ymm15,ymm15,ymm3 vprord ymm12,ymm12,0x8 vprord ymm13,ymm13,0x8 vprord ymm14,ymm14,0x8 vprord ymm15,ymm15,0x8 vpaddd ymm8,ymm8,ymm12 vpaddd ymm9,ymm9,ymm13 vpaddd ymm10,ymm10,ymm14 vpaddd ymm11,ymm11,ymm15 vpxord ymm4,ymm4,ymm8 vpxord ymm5,ymm5,ymm9 vpxord ymm6,ymm6,ymm10 vpxord ymm7,ymm7,ymm11 vprord ymm4,ymm4,0x7 vprord ymm5,ymm5,0x7 vprord ymm6,ymm6,0x7 vprord ymm7,ymm7,0x7 vpaddd ymm0,ymm0,ymm23 vpaddd ymm1,ymm1,ymm21 vpaddd ymm2,ymm2,ymm16 vpaddd ymm3,ymm3,ymm22 vpaddd ymm0,ymm0,ymm5 vpaddd ymm1,ymm1,ymm6 vpaddd ymm2,ymm2,ymm7 vpaddd ymm3,ymm3,ymm4 vpxord ymm15,ymm15,ymm0 vpxord ymm12,ymm12,ymm1 vpxord ymm13,ymm13,ymm2 vpxord ymm14,ymm14,ymm3 vprord ymm15,ymm15,0x10 vprord ymm12,ymm12,0x10 vprord ymm13,ymm13,0x10 vprord ymm14,ymm14,0x10 vpaddd ymm10,ymm10,ymm15 vpaddd ymm11,ymm11,ymm12 vpaddd ymm8,ymm8,ymm13 vpaddd ymm9,ymm9,ymm14 vpxord ymm5,ymm5,ymm10 vpxord ymm6,ymm6,ymm11 vpxord ymm7,ymm7,ymm8 vpxord ymm4,ymm4,ymm9 vprord ymm5,ymm5,0xc vprord ymm6,ymm6,0xc vprord ymm7,ymm7,0xc vprord ymm4,ymm4,0xc vpaddd ymm0,ymm0,ymm18 vpaddd ymm1,ymm1,ymm19 vpaddd ymm2,ymm2,ymm17 vpaddd ymm3,ymm3,ymm20 vpaddd ymm0,ymm0,ymm5 vpaddd ymm1,ymm1,ymm6 vpaddd ymm2,ymm2,ymm7 vpaddd ymm3,ymm3,ymm4 vpxord ymm15,ymm15,ymm0 vpxord ymm12,ymm12,ymm1 vpxord ymm13,ymm13,ymm2 vpxord ymm14,ymm14,ymm3 vprord ymm15,ymm15,0x8 vprord ymm12,ymm12,0x8 vprord ymm13,ymm13,0x8 vprord ymm14,ymm14,0x8 vpaddd ymm10,ymm10,ymm15 vpaddd ymm11,ymm11,ymm12 vpaddd ymm8,ymm8,ymm13 vpaddd ymm9,ymm9,ymm14 vpxord ymm5,ymm5,ymm10 vpxord ymm6,ymm6,ymm11 vpxord ymm7,ymm7,ymm8 vpxord ymm4,ymm4,ymm9 vprord ymm5,ymm5,0x7 vprord ymm6,ymm6,0x7 vprord ymm7,ymm7,0x7 vprord ymm4,ymm4,0x7 vpaddd ymm0,ymm0,ymm25 vpaddd ymm1,ymm1,ymm27 vpaddd ymm2,ymm2,ymm24 vpaddd ymm3,ymm3,ymm31 vpaddd ymm0,ymm0,ymm4 vpaddd ymm1,ymm1,ymm5 vpaddd ymm2,ymm2,ymm6 vpaddd ymm3,ymm3,ymm7 vpxord ymm12,ymm12,ymm0 vpxord ymm13,ymm13,ymm1 vpxord ymm14,ymm14,ymm2 vpxord ymm15,ymm15,ymm3 vprord ymm12,ymm12,0x10 vprord ymm13,ymm13,0x10 vprord ymm14,ymm14,0x10 vprord ymm15,ymm15,0x10 vpaddd ymm8,ymm8,ymm12 vpaddd ymm9,ymm9,ymm13 vpaddd ymm10,ymm10,ymm14 vpaddd ymm11,ymm11,ymm15 vpxord ymm4,ymm4,ymm8 vpxord ymm5,ymm5,ymm9 vpxord ymm6,ymm6,ymm10 vpxord ymm7,ymm7,ymm11 vprord ymm4,ymm4,0xc vprord ymm5,ymm5,0xc vprord ymm6,ymm6,0xc vprord ymm7,ymm7,0xc vpaddd ymm0,ymm0,ymm30 vpaddd ymm1,ymm1,ymm21 vpaddd ymm2,ymm2,ymm28 vpaddd ymm3,ymm3,ymm17 vpaddd ymm0,ymm0,ymm4 vpaddd ymm1,ymm1,ymm5 vpaddd ymm2,ymm2,ymm6 vpaddd ymm3,ymm3,ymm7 vpxord ymm12,ymm12,ymm0 vpxord ymm13,ymm13,ymm1 vpxord ymm14,ymm14,ymm2 vpxord ymm15,ymm15,ymm3 vprord ymm12,ymm12,0x8 vprord ymm13,ymm13,0x8 vprord ymm14,ymm14,0x8 vprord ymm15,ymm15,0x8 vpaddd ymm8,ymm8,ymm12 vpaddd ymm9,ymm9,ymm13 vpaddd ymm10,ymm10,ymm14 vpaddd ymm11,ymm11,ymm15 vpxord ymm4,ymm4,ymm8 vpxord ymm5,ymm5,ymm9 vpxord ymm6,ymm6,ymm10 vpxord ymm7,ymm7,ymm11 vprord ymm4,ymm4,0x7 vprord ymm5,ymm5,0x7 vprord ymm6,ymm6,0x7 vprord ymm7,ymm7,0x7 vpaddd ymm0,ymm0,ymm29 vpaddd ymm1,ymm1,ymm16 vpaddd ymm2,ymm2,ymm18 vpaddd ymm3,ymm3,ymm20 vpaddd ymm0,ymm0,ymm5 vpaddd ymm1,ymm1,ymm6 vpaddd ymm2,ymm2,ymm7 vpaddd ymm3,ymm3,ymm4 vpxord ymm15,ymm15,ymm0 vpxord ymm12,ymm12,ymm1 vpxord ymm13,ymm13,ymm2 vpxord ymm14,ymm14,ymm3 vprord ymm15,ymm15,0x10 vprord ymm12,ymm12,0x10 vprord ymm13,ymm13,0x10 vprord ymm14,ymm14,0x10 vpaddd ymm10,ymm10,ymm15 vpaddd ymm11,ymm11,ymm12 vpaddd ymm8,ymm8,ymm13 vpaddd ymm9,ymm9,ymm14 vpxord ymm5,ymm5,ymm10 vpxord ymm6,ymm6,ymm11 vpxord ymm7,ymm7,ymm8 vpxord ymm4,ymm4,ymm9 vprord ymm5,ymm5,0xc vprord ymm6,ymm6,0xc vprord ymm7,ymm7,0xc vprord ymm4,ymm4,0xc vpaddd ymm0,ymm0,ymm19 vpaddd ymm1,ymm1,ymm26 vpaddd ymm2,ymm2,ymm22 vpaddd ymm3,ymm3,ymm23 vpaddd ymm0,ymm0,ymm5 vpaddd ymm1,ymm1,ymm6 vpaddd ymm2,ymm2,ymm7 vpaddd ymm3,ymm3,ymm4 vpxord ymm15,ymm15,ymm0 vpxord ymm12,ymm12,ymm1 vpxord ymm13,ymm13,ymm2 vpxord ymm14,ymm14,ymm3 vprord ymm15,ymm15,0x8 vprord ymm12,ymm12,0x8 vprord ymm13,ymm13,0x8 vprord ymm14,ymm14,0x8 vpaddd ymm10,ymm10,ymm15 vpaddd ymm11,ymm11,ymm12 vpaddd ymm8,ymm8,ymm13 vpaddd ymm9,ymm9,ymm14 vpxord ymm5,ymm5,ymm10 vpxord ymm6,ymm6,ymm11 vpxord ymm7,ymm7,ymm8 vpxord ymm4,ymm4,ymm9 vprord ymm5,ymm5,0x7 vprord ymm6,ymm6,0x7 vprord ymm7,ymm7,0x7 vprord ymm4,ymm4,0x7 vpaddd ymm0,ymm0,ymm27 vpaddd ymm1,ymm1,ymm21 vpaddd ymm2,ymm2,ymm17 vpaddd ymm3,ymm3,ymm24 vpaddd ymm0,ymm0,ymm4 vpaddd ymm1,ymm1,ymm5 vpaddd ymm2,ymm2,ymm6 vpaddd ymm3,ymm3,ymm7 vpxord ymm12,ymm12,ymm0 vpxord ymm13,ymm13,ymm1 vpxord ymm14,ymm14,ymm2 vpxord ymm15,ymm15,ymm3 vprord ymm12,ymm12,0x10 vprord ymm13,ymm13,0x10 vprord ymm14,ymm14,0x10 vprord ymm15,ymm15,0x10 vpaddd ymm8,ymm8,ymm12 vpaddd ymm9,ymm9,ymm13 vpaddd ymm10,ymm10,ymm14 vpaddd ymm11,ymm11,ymm15 vpxord ymm4,ymm4,ymm8 vpxord ymm5,ymm5,ymm9 vpxord ymm6,ymm6,ymm10 vpxord ymm7,ymm7,ymm11 vprord ymm4,ymm4,0xc vprord ymm5,ymm5,0xc vprord ymm6,ymm6,0xc vprord ymm7,ymm7,0xc vpaddd ymm0,ymm0,ymm31 vpaddd ymm1,ymm1,ymm16 vpaddd ymm2,ymm2,ymm25 vpaddd ymm3,ymm3,ymm22 vpaddd ymm0,ymm0,ymm4 vpaddd ymm1,ymm1,ymm5 vpaddd ymm2,ymm2,ymm6 vpaddd ymm3,ymm3,ymm7 vpxord ymm12,ymm12,ymm0 vpxord ymm13,ymm13,ymm1 vpxord ymm14,ymm14,ymm2 vpxord ymm15,ymm15,ymm3 vprord ymm12,ymm12,0x8 vprord ymm13,ymm13,0x8 vprord ymm14,ymm14,0x8 vprord ymm15,ymm15,0x8 vpaddd ymm8,ymm8,ymm12 vpaddd ymm9,ymm9,ymm13 vpaddd ymm10,ymm10,ymm14 vpaddd ymm11,ymm11,ymm15 vpxord ymm4,ymm4,ymm8 vpxord ymm5,ymm5,ymm9 vpxord ymm6,ymm6,ymm10 vpxord ymm7,ymm7,ymm11 vprord ymm4,ymm4,0x7 vprord ymm5,ymm5,0x7 vprord ymm6,ymm6,0x7 vprord ymm7,ymm7,0x7 vpaddd ymm0,ymm0,ymm30 vpaddd ymm1,ymm1,ymm18 vpaddd ymm2,ymm2,ymm19 vpaddd ymm3,ymm3,ymm23 vpaddd ymm0,ymm0,ymm5 vpaddd ymm1,ymm1,ymm6 vpaddd ymm2,ymm2,ymm7 vpaddd ymm3,ymm3,ymm4 vpxord ymm15,ymm15,ymm0 vpxord ymm12,ymm12,ymm1 vpxord ymm13,ymm13,ymm2 vpxord ymm14,ymm14,ymm3 vprord ymm15,ymm15,0x10 vprord ymm12,ymm12,0x10 vprord ymm13,ymm13,0x10 vprord ymm14,ymm14,0x10 vpaddd ymm10,ymm10,ymm15 vpaddd ymm11,ymm11,ymm12 vpaddd ymm8,ymm8,ymm13 vpaddd ymm9,ymm9,ymm14 vpxord ymm5,ymm5,ymm10 vpxord ymm6,ymm6,ymm11 vpxord ymm7,ymm7,ymm8 vpxord ymm4,ymm4,ymm9 vprord ymm5,ymm5,0xc vprord ymm6,ymm6,0xc vprord ymm7,ymm7,0xc vprord ymm4,ymm4,0xc vpaddd ymm0,ymm0,ymm26 vpaddd ymm1,ymm1,ymm28 vpaddd ymm2,ymm2,ymm20 vpaddd ymm3,ymm3,ymm29 vpaddd ymm0,ymm0,ymm5 vpaddd ymm1,ymm1,ymm6 vpaddd ymm2,ymm2,ymm7 vpaddd ymm3,ymm3,ymm4 vpxord ymm15,ymm15,ymm0 vpxord ymm12,ymm12,ymm1 vpxord ymm13,ymm13,ymm2 vpxord ymm14,ymm14,ymm3 vprord ymm15,ymm15,0x8 vprord ymm12,ymm12,0x8 vprord ymm13,ymm13,0x8 vprord ymm14,ymm14,0x8 vpaddd ymm10,ymm10,ymm15 vpaddd ymm11,ymm11,ymm12 vpaddd ymm8,ymm8,ymm13 vpaddd ymm9,ymm9,ymm14 vpxord ymm5,ymm5,ymm10 vpxord ymm6,ymm6,ymm11 vpxord ymm7,ymm7,ymm8 vpxord ymm4,ymm4,ymm9 vprord ymm5,ymm5,0x7 vprord ymm6,ymm6,0x7 vprord ymm7,ymm7,0x7 vprord ymm4,ymm4,0x7 vpxor ymm0,ymm0,ymm8 vpxor ymm1,ymm1,ymm9 vpxor ymm2,ymm2,ymm10 vpxor ymm3,ymm3,ymm11 vpxor ymm4,ymm4,ymm12 vpxor ymm5,ymm5,ymm13 vpxor ymm6,ymm6,ymm14 vpxor ymm7,ymm7,ymm15 vpxord ymm8,ymm8,DWORD PTR [rdi]{1to8} vpxord ymm9,ymm9,DWORD PTR [rdi+0x4]{1to8} vpxord ymm10,ymm10,DWORD PTR [rdi+0x8]{1to8} vpxord ymm11,ymm11,DWORD PTR [rdi+0xc]{1to8} vpxord ymm12,ymm12,DWORD PTR [rdi+0x10]{1to8} vpxord ymm13,ymm13,DWORD PTR [rdi+0x14]{1to8} vpxord ymm14,ymm14,DWORD PTR [rdi+0x18]{1to8} vpxord ymm15,ymm15,DWORD PTR [rdi+0x1c]{1to8} vpunpckldq ymm16,ymm0,ymm1 vpunpckhdq ymm17,ymm0,ymm1 vpunpckldq ymm18,ymm2,ymm3 vpunpckhdq ymm19,ymm2,ymm3 vpunpckldq ymm20,ymm4,ymm5 vpunpckhdq ymm21,ymm4,ymm5 vpunpckldq ymm22,ymm6,ymm7 vpunpckhdq ymm23,ymm6,ymm7 vpunpckldq ymm24,ymm8,ymm9 vpunpckhdq ymm25,ymm8,ymm9 vpunpckldq ymm26,ymm10,ymm11 vpunpckhdq ymm27,ymm10,ymm11 vpunpckldq ymm28,ymm12,ymm13 vpunpckhdq ymm29,ymm12,ymm13 vpunpckldq ymm30,ymm14,ymm15 vpunpckhdq ymm31,ymm14,ymm15 vpunpcklqdq ymm0,ymm16,ymm18 vpunpckhqdq ymm1,ymm16,ymm18 vpunpcklqdq ymm2,ymm17,ymm19 vpunpckhqdq ymm3,ymm17,ymm19 vpunpcklqdq ymm4,ymm20,ymm22 vpunpckhqdq ymm5,ymm20,ymm22 vpunpcklqdq ymm6,ymm21,ymm23 vpunpckhqdq ymm7,ymm21,ymm23 vpunpcklqdq ymm8,ymm24,ymm26 vpunpckhqdq ymm9,ymm24,ymm26 vpunpcklqdq ymm10,ymm25,ymm27 vpunpckhqdq ymm11,ymm25,ymm27 vpunpcklqdq ymm12,ymm28,ymm30 vpunpckhqdq ymm13,ymm28,ymm30 vpunpcklqdq ymm14,ymm29,ymm31 vpunpckhqdq ymm15,ymm29,ymm31 vshufi32x4 ymm16,ymm0,ymm4,0x0 vshufi32x4 ymm17,ymm8,ymm12,0x0 vshufi32x4 ymm18,ymm1,ymm5,0x0 vshufi32x4 ymm19,ymm9,ymm13,0x0 vshufi32x4 ymm20,ymm2,ymm6,0x0 vshufi32x4 ymm21,ymm10,ymm14,0x0 vshufi32x4 ymm22,ymm3,ymm7,0x0 vshufi32x4 ymm23,ymm11,ymm15,0x0 vshufi32x4 ymm24,ymm0,ymm4,0x3 vshufi32x4 ymm25,ymm8,ymm12,0x3 vshufi32x4 ymm26,ymm1,ymm5,0x3 vshufi32x4 ymm27,ymm9,ymm13,0x3 vshufi32x4 ymm28,ymm2,ymm6,0x3 vshufi32x4 ymm29,ymm10,ymm14,0x3 vshufi32x4 ymm30,ymm3,ymm7,0x3 vshufi32x4 ymm31,ymm11,ymm15,0x3 vmovdqu32 YMMWORD PTR [r9],ymm16 vmovdqu32 YMMWORD PTR [r9+0x20],ymm17 vmovdqu32 YMMWORD PTR [r9+0x40],ymm18 vmovdqu32 YMMWORD PTR [r9+0x60],ymm19 vmovdqu32 YMMWORD PTR [r9+0x80],ymm20 vmovdqu32 YMMWORD PTR [r9+0xa0],ymm21 vmovdqu32 YMMWORD PTR [r9+0xc0],ymm22 vmovdqu32 YMMWORD PTR [r9+0xe0],ymm23 vmovdqu32 YMMWORD PTR [r9+0x100],ymm24 vmovdqu32 YMMWORD PTR [r9+0x120],ymm25 vmovdqu32 YMMWORD PTR [r9+0x140],ymm26 vmovdqu32 YMMWORD PTR [r9+0x160],ymm27 vmovdqu32 YMMWORD PTR [r9+0x180],ymm28 vmovdqu32 YMMWORD PTR [r9+0x1a0],ymm29 vmovdqu32 YMMWORD PTR [r9+0x1c0],ymm30 vmovdqu32 YMMWORD PTR [r9+0x1e0],ymm31 vmovdqa ymm0,YMMWORD PTR [rsp+0x20] vmovdqa ymm1,YMMWORD PTR [rsp+0x60] vmovdqa YMMWORD PTR [rsp],ymm0 vmovdqa YMMWORD PTR [rsp+0x40],ymm1 add r9,0x200 sub r10,0x8 2: test r10,0x4 je 2f vbroadcasti32x4 zmm0,XMMWORD PTR [rdi] vbroadcasti32x4 zmm1,XMMWORD PTR [rdi+0x10] vbroadcasti32x4 zmm2,XMMWORD PTR [BLAKE3_IV+rip] vmovdqa xmm12,XMMWORD PTR [rsp] vmovdqa xmm13,XMMWORD PTR [rsp+0x40] vpunpckldq xmm14,xmm12,xmm13 vpunpckhdq xmm15,xmm12,xmm13 vpermq ymm14,ymm14,0xdc vpermq ymm15,ymm15,0xdc vpbroadcastd zmm12,edx vinserti64x4 zmm13,zmm14,ymm15,0x1 mov eax,0x4444 kmovw k2,eax vpblendmd zmm13{k2},zmm13,zmm12 vpbroadcastd zmm15,r8d mov eax,0x8888 kmovw k4,eax vpblendmd zmm3{k4},zmm13,zmm15 mov eax,0xaaaa kmovw k3,eax vbroadcasti32x4 zmm8,XMMWORD PTR [rsi] vbroadcasti32x4 zmm9,XMMWORD PTR [rsi+0x10] vshufps zmm4,zmm8,zmm9,0x88 vshufps zmm5,zmm8,zmm9,0xdd vbroadcasti32x4 zmm8,XMMWORD PTR [rsi+0x20] vbroadcasti32x4 zmm9,XMMWORD PTR [rsi+0x30] vshufps zmm6,zmm8,zmm9,0x88 vshufps zmm7,zmm8,zmm9,0xdd vpshufd zmm6,zmm6,0x93 vpshufd zmm7,zmm7,0x93 mov al,0x7 3: vpaddd zmm0,zmm0,zmm4 vpaddd zmm0,zmm0,zmm1 vpxord zmm3,zmm3,zmm0 vprord zmm3,zmm3,0x10 vpaddd zmm2,zmm2,zmm3 vpxord zmm1,zmm1,zmm2 vprord zmm1,zmm1,0xc vpaddd zmm0,zmm0,zmm5 vpaddd zmm0,zmm0,zmm1 vpxord zmm3,zmm3,zmm0 vprord zmm3,zmm3,0x8 vpaddd zmm2,zmm2,zmm3 vpxord zmm1,zmm1,zmm2 vprord zmm1,zmm1,0x7 vpshufd zmm0,zmm0,0x93 vpshufd zmm3,zmm3,0x4e vpshufd zmm2,zmm2,0x39 vpaddd zmm0,zmm0,zmm6 vpaddd zmm0,zmm0,zmm1 vpxord zmm3,zmm3,zmm0 vprord zmm3,zmm3,0x10 vpaddd zmm2,zmm2,zmm3 vpxord zmm1,zmm1,zmm2 vprord zmm1,zmm1,0xc vpaddd zmm0,zmm0,zmm7 vpaddd zmm0,zmm0,zmm1 vpxord zmm3,zmm3,zmm0 vprord zmm3,zmm3,0x8 vpaddd zmm2,zmm2,zmm3 vpxord zmm1,zmm1,zmm2 vprord zmm1,zmm1,0x7 vpshufd zmm0,zmm0,0x39 vpshufd zmm3,zmm3,0x4e vpshufd zmm2,zmm2,0x93 dec al je 3f vshufps zmm8,zmm4,zmm5,0xd6 vpshufd zmm9,zmm4,0xf vpshufd zmm4,zmm8,0x39 vshufps zmm8,zmm6,zmm7,0xfa vpblendmd zmm9{k3},zmm9,zmm8 vpunpcklqdq zmm8,zmm7,zmm5 vpblendmd zmm8{k4},zmm8,zmm6 vpshufd zmm8,zmm8,0x78 vpunpckhdq zmm5,zmm5,zmm7 vpunpckldq zmm6,zmm6,zmm5 vpshufd zmm7,zmm6,0x1e vmovdqa32 zmm5,zmm9 vmovdqa32 zmm6,zmm8 jmp 3b 3: vpxord zmm0,zmm0,zmm2 vpxord zmm1,zmm1,zmm3 vbroadcasti32x4 zmm8,XMMWORD PTR [rdi] vbroadcasti32x4 zmm9,XMMWORD PTR [rdi+0x10] vpxord zmm2,zmm2,zmm8 vpxord zmm3,zmm3,zmm9 vmovdqu XMMWORD PTR [r9],xmm0 vmovdqu XMMWORD PTR [r9+0x10],xmm1 vmovdqu XMMWORD PTR [r9+0x20],xmm2 vmovdqu XMMWORD PTR [r9+0x30],xmm3 vextracti128 XMMWORD PTR [r9+0x40],ymm0,0x1 vextracti128 XMMWORD PTR [r9+0x50],ymm1,0x1 vextracti128 XMMWORD PTR [r9+0x60],ymm2,0x1 vextracti128 XMMWORD PTR [r9+0x70],ymm3,0x1 vextracti32x4 XMMWORD PTR [r9+0x80],zmm0,0x2 vextracti32x4 XMMWORD PTR [r9+0x90],zmm1,0x2 vextracti32x4 XMMWORD PTR [r9+0xa0],zmm2,0x2 vextracti32x4 XMMWORD PTR [r9+0xb0],zmm3,0x2 vextracti32x4 XMMWORD PTR [r9+0xc0],zmm0,0x3 vextracti32x4 XMMWORD PTR [r9+0xd0],zmm1,0x3 vextracti32x4 XMMWORD PTR [r9+0xe0],zmm2,0x3 vextracti32x4 XMMWORD PTR [r9+0xf0],zmm3,0x3 vmovdqa xmm0,XMMWORD PTR [rsp+0x10] vmovdqa xmm1,XMMWORD PTR [rsp+0x50] vmovdqa XMMWORD PTR [rsp],xmm0 vmovdqa XMMWORD PTR [rsp+0x40],xmm1 add r9,0x100 sub r10,0x4 2: test r10,0x2 je 2f vbroadcasti128 ymm0,XMMWORD PTR [rdi] vbroadcasti128 ymm1,XMMWORD PTR [rdi+0x10] vmovd xmm13,DWORD PTR [rsp] vpinsrd xmm13,xmm13,DWORD PTR [rsp+0x40],0x1 vpinsrd xmm13,xmm13,edx,0x2 vmovd xmm14,DWORD PTR [rsp+0x4] vpinsrd xmm14,xmm14,DWORD PTR [rsp+0x44],0x1 vpinsrd xmm14,xmm14,edx,0x2 vinserti128 ymm13,ymm13,xmm14,0x1 vbroadcasti128 ymm2,XMMWORD PTR [BLAKE3_IV+rip] vpbroadcastd ymm8,r8d vpblendd ymm3,ymm13,ymm8,0x88 vbroadcasti128 ymm8,XMMWORD PTR [rsi] vbroadcasti128 ymm9,XMMWORD PTR [rsi+0x10] vshufps ymm4,ymm8,ymm9,0x88 vshufps ymm5,ymm8,ymm9,0xdd vbroadcasti128 ymm8,XMMWORD PTR [rsi+0x20] vbroadcasti128 ymm9,XMMWORD PTR [rsi+0x30] vshufps ymm6,ymm8,ymm9,0x88 vshufps ymm7,ymm8,ymm9,0xdd vpshufd ymm6,ymm6,0x93 vpshufd ymm7,ymm7,0x93 mov al,0x7 3: vpaddd ymm0,ymm0,ymm4 vpaddd ymm0,ymm0,ymm1 vpxord ymm3,ymm3,ymm0 vprord ymm3,ymm3,0x10 vpaddd ymm2,ymm2,ymm3 vpxord ymm1,ymm1,ymm2 vprord ymm1,ymm1,0xc vpaddd ymm0,ymm0,ymm5 vpaddd ymm0,ymm0,ymm1 vpxord ymm3,ymm3,ymm0 vprord ymm3,ymm3,0x8 vpaddd ymm2,ymm2,ymm3 vpxord ymm1,ymm1,ymm2 vprord ymm1,ymm1,0x7 vpshufd ymm0,ymm0,0x93 vpshufd ymm3,ymm3,0x4e vpshufd ymm2,ymm2,0x39 vpaddd ymm0,ymm0,ymm6 vpaddd ymm0,ymm0,ymm1 vpxord ymm3,ymm3,ymm0 vprord ymm3,ymm3,0x10 vpaddd ymm2,ymm2,ymm3 vpxord ymm1,ymm1,ymm2 vprord ymm1,ymm1,0xc vpaddd ymm0,ymm0,ymm7 vpaddd ymm0,ymm0,ymm1 vpxord ymm3,ymm3,ymm0 vprord ymm3,ymm3,0x8 vpaddd ymm2,ymm2,ymm3 vpxord ymm1,ymm1,ymm2 vprord ymm1,ymm1,0x7 vpshufd ymm0,ymm0,0x39 vpshufd ymm3,ymm3,0x4e vpshufd ymm2,ymm2,0x93 dec al je 3f vshufps ymm8,ymm4,ymm5,0xd6 vpshufd ymm9,ymm4,0xf vpshufd ymm4,ymm8,0x39 vshufps ymm8,ymm6,ymm7,0xfa vpblendd ymm9,ymm9,ymm8,0xaa vpunpcklqdq ymm8,ymm7,ymm5 vpblendd ymm8,ymm8,ymm6,0x88 vpshufd ymm8,ymm8,0x78 vpunpckhdq ymm5,ymm5,ymm7 vpunpckldq ymm6,ymm6,ymm5 vpshufd ymm7,ymm6,0x1e vmovdqa ymm5,ymm9 vmovdqa ymm6,ymm8 jmp 3b 3: vpxor ymm0,ymm0,ymm2 vpxor ymm1,ymm1,ymm3 vbroadcasti128 ymm8,XMMWORD PTR [rdi] vbroadcasti128 ymm9,XMMWORD PTR [rdi+0x10] vpxor ymm2,ymm2,ymm8 vpxor ymm3,ymm3,ymm9 vmovdqu XMMWORD PTR [r9],xmm0 vmovdqu XMMWORD PTR [r9+0x10],xmm1 vmovdqu XMMWORD PTR [r9+0x20],xmm2 vmovdqu XMMWORD PTR [r9+0x30],xmm3 vextracti128 XMMWORD PTR [r9+0x40],ymm0,0x1 vextracti128 XMMWORD PTR [r9+0x50],ymm1,0x1 vextracti128 XMMWORD PTR [r9+0x60],ymm2,0x1 vextracti128 XMMWORD PTR [r9+0x70],ymm3,0x1 vmovdqu xmm0,XMMWORD PTR [rsp+0x8] vmovdqu xmm1,XMMWORD PTR [rsp+0x48] vmovdqa XMMWORD PTR [rsp],xmm0 vmovdqa XMMWORD PTR [rsp+0x40],xmm1 add r9,0x80 sub r10,0x2 2: test r10,0x1 je 9b vmovdqu xmm0,XMMWORD PTR [rdi] vmovdqu xmm1,XMMWORD PTR [rdi+0x10] vmovd xmm14,DWORD PTR [rsp] vpinsrd xmm14,xmm14,DWORD PTR [rsp+0x40],0x1 vpinsrd xmm14,xmm14,edx,0x2 vmovdqa xmm2,XMMWORD PTR [BLAKE3_IV+rip] vpinsrd xmm3,xmm14,r8d,0x3 vmovups xmm8,XMMWORD PTR [rsi] vmovups xmm9,XMMWORD PTR [rsi+0x10] vshufps xmm4,xmm8,xmm9,0x88 vshufps xmm5,xmm8,xmm9,0xdd vmovups xmm8,XMMWORD PTR [rsi+0x20] vmovups xmm9,XMMWORD PTR [rsi+0x30] vshufps xmm6,xmm8,xmm9,0x88 vshufps xmm7,xmm8,xmm9,0xdd vpshufd xmm6,xmm6,0x93 vpshufd xmm7,xmm7,0x93 mov al,0x7 3: vpaddd xmm0,xmm0,xmm4 vpaddd xmm0,xmm0,xmm1 vpxord xmm3,xmm3,xmm0 vprord xmm3,xmm3,0x10 vpaddd xmm2,xmm2,xmm3 vpxord xmm1,xmm1,xmm2 vprord xmm1,xmm1,0xc vpaddd xmm0,xmm0,xmm5 vpaddd xmm0,xmm0,xmm1 vpxord xmm3,xmm3,xmm0 vprord xmm3,xmm3,0x8 vpaddd xmm2,xmm2,xmm3 vpxord xmm1,xmm1,xmm2 vprord xmm1,xmm1,0x7 vpshufd xmm0,xmm0,0x93 vpshufd xmm3,xmm3,0x4e vpshufd xmm2,xmm2,0x39 vpaddd xmm0,xmm0,xmm6 vpaddd xmm0,xmm0,xmm1 vpxord xmm3,xmm3,xmm0 vprord xmm3,xmm3,0x10 vpaddd xmm2,xmm2,xmm3 vpxord xmm1,xmm1,xmm2 vprord xmm1,xmm1,0xc vpaddd xmm0,xmm0,xmm7 vpaddd xmm0,xmm0,xmm1 vpxord xmm3,xmm3,xmm0 vprord xmm3,xmm3,0x8 vpaddd xmm2,xmm2,xmm3 vpxord xmm1,xmm1,xmm2 vprord xmm1,xmm1,0x7 vpshufd xmm0,xmm0,0x39 vpshufd xmm3,xmm3,0x4e vpshufd xmm2,xmm2,0x93 dec al je 3f vshufps xmm8,xmm4,xmm5,0xd6 vpshufd xmm9,xmm4,0xf vpshufd xmm4,xmm8,0x39 vshufps xmm8,xmm6,xmm7,0xfa vpblendd xmm9,xmm9,xmm8,0xaa vpunpcklqdq xmm8,xmm7,xmm5 vpblendd xmm8,xmm8,xmm6,0x88 vpshufd xmm8,xmm8,0x78 vpunpckhdq xmm5,xmm5,xmm7 vpunpckldq xmm6,xmm6,xmm5 vpshufd xmm7,xmm6,0x1e vmovdqa xmm5,xmm9 vmovdqa xmm6,xmm8 jmp 3b 3: vpxor xmm0,xmm0,xmm2 vpxor xmm1,xmm1,xmm3 vpxor xmm2,xmm2,XMMWORD PTR [rdi] vpxor xmm3,xmm3,XMMWORD PTR [rdi+0x10] vmovdqu XMMWORD PTR [r9],xmm0 vmovdqu XMMWORD PTR [r9+0x10],xmm1 vmovdqu XMMWORD PTR [r9+0x20],xmm2 vmovdqu XMMWORD PTR [r9+0x30],xmm3 jmp 9b #ifdef __APPLE__ .static_data #else .section .rodata #endif .p2align 6 INDEX0: .long 0, 1, 2, 3, 16, 17, 18, 19 .long 8, 9, 10, 11, 24, 25, 26, 27 INDEX1: .long 4, 5, 6, 7, 20, 21, 22, 23 .long 12, 13, 14, 15, 28, 29, 30, 31 ADD0: .long 0, 1, 2, 3, 4, 5, 6, 7 .long 8, 9, 10, 11, 12, 13, 14, 15 ADD1: .long 1 ADD16: .long 16 BLAKE3_BLOCK_LEN: .long 64 .p2align 6 BLAKE3_IV: BLAKE3_IV_0: .long 0x6A09E667 BLAKE3_IV_1: .long 0xBB67AE85 BLAKE3_IV_2: .long 0x3C6EF372 BLAKE3_IV_3: .long 0xA54FF53A librecast/libs/blake3/c/blake3_avx512_x86-64_windows_gnu.S000066400000000000000000002615731502456746400233470ustar00rootroot00000000000000.intel_syntax noprefix .global _blake3_hash_many_avx512 .global blake3_hash_many_avx512 .global blake3_compress_in_place_avx512 .global _blake3_compress_in_place_avx512 .global blake3_compress_xof_avx512 .global _blake3_compress_xof_avx512 .section .text .p2align 6 _blake3_hash_many_avx512: blake3_hash_many_avx512: push r15 push r14 push r13 push r12 push rdi push rsi push rbx push rbp mov rbp, rsp sub rsp, 304 and rsp, 0xFFFFFFFFFFFFFFC0 vmovdqa xmmword ptr [rsp+0x90], xmm6 vmovdqa xmmword ptr [rsp+0xA0], xmm7 vmovdqa xmmword ptr [rsp+0xB0], xmm8 vmovdqa xmmword ptr [rsp+0xC0], xmm9 vmovdqa xmmword ptr [rsp+0xD0], xmm10 vmovdqa xmmword ptr [rsp+0xE0], xmm11 vmovdqa xmmword ptr [rsp+0xF0], xmm12 vmovdqa xmmword ptr [rsp+0x100], xmm13 vmovdqa xmmword ptr [rsp+0x110], xmm14 vmovdqa xmmword ptr [rsp+0x120], xmm15 mov rdi, rcx mov rsi, rdx mov rdx, r8 mov rcx, r9 mov r8, qword ptr [rbp+0x68] movzx r9, byte ptr [rbp+0x70] neg r9 kmovw k1, r9d vmovd xmm0, r8d vpbroadcastd ymm0, xmm0 shr r8, 32 vmovd xmm1, r8d vpbroadcastd ymm1, xmm1 vmovdqa ymm4, ymm1 vmovdqa ymm5, ymm1 vpaddd ymm2, ymm0, ymmword ptr [ADD0+rip] vpaddd ymm3, ymm0, ymmword ptr [ADD0+32+rip] vpcmpltud k2, ymm2, ymm0 vpcmpltud k3, ymm3, ymm0 vpaddd ymm4 {k2}, ymm4, dword ptr [ADD1+rip] {1to8} vpaddd ymm5 {k3}, ymm5, dword ptr [ADD1+rip] {1to8} knotw k2, k1 vmovdqa32 ymm2 {k2}, ymm0 vmovdqa32 ymm3 {k2}, ymm0 vmovdqa32 ymm4 {k2}, ymm1 vmovdqa32 ymm5 {k2}, ymm1 vmovdqa ymmword ptr [rsp], ymm2 vmovdqa ymmword ptr [rsp+0x20], ymm3 vmovdqa ymmword ptr [rsp+0x40], ymm4 vmovdqa ymmword ptr [rsp+0x60], ymm5 shl rdx, 6 mov qword ptr [rsp+0x80], rdx cmp rsi, 16 jc 3f 2: vpbroadcastd zmm0, dword ptr [rcx] vpbroadcastd zmm1, dword ptr [rcx+0x1*0x4] vpbroadcastd zmm2, dword ptr [rcx+0x2*0x4] vpbroadcastd zmm3, dword ptr [rcx+0x3*0x4] vpbroadcastd zmm4, dword ptr [rcx+0x4*0x4] vpbroadcastd zmm5, dword ptr [rcx+0x5*0x4] vpbroadcastd zmm6, dword ptr [rcx+0x6*0x4] vpbroadcastd zmm7, dword ptr [rcx+0x7*0x4] movzx eax, byte ptr [rbp+0x78] movzx ebx, byte ptr [rbp+0x80] or eax, ebx xor edx, edx .p2align 5 9: movzx ebx, byte ptr [rbp+0x88] or ebx, eax add rdx, 64 cmp rdx, qword ptr [rsp+0x80] cmove eax, ebx mov dword ptr [rsp+0x88], eax mov r8, qword ptr [rdi] mov r9, qword ptr [rdi+0x8] mov r10, qword ptr [rdi+0x10] mov r11, qword ptr [rdi+0x18] mov r12, qword ptr [rdi+0x40] mov r13, qword ptr [rdi+0x48] mov r14, qword ptr [rdi+0x50] mov r15, qword ptr [rdi+0x58] vmovdqu32 ymm16, ymmword ptr [rdx+r8-0x2*0x20] vinserti64x4 zmm16, zmm16, ymmword ptr [rdx+r12-0x2*0x20], 0x01 vmovdqu32 ymm17, ymmword ptr [rdx+r9-0x2*0x20] vinserti64x4 zmm17, zmm17, ymmword ptr [rdx+r13-0x2*0x20], 0x01 vpunpcklqdq zmm8, zmm16, zmm17 vpunpckhqdq zmm9, zmm16, zmm17 vmovdqu32 ymm18, ymmword ptr [rdx+r10-0x2*0x20] vinserti64x4 zmm18, zmm18, ymmword ptr [rdx+r14-0x2*0x20], 0x01 vmovdqu32 ymm19, ymmword ptr [rdx+r11-0x2*0x20] vinserti64x4 zmm19, zmm19, ymmword ptr [rdx+r15-0x2*0x20], 0x01 vpunpcklqdq zmm10, zmm18, zmm19 vpunpckhqdq zmm11, zmm18, zmm19 mov r8, qword ptr [rdi+0x20] mov r9, qword ptr [rdi+0x28] mov r10, qword ptr [rdi+0x30] mov r11, qword ptr [rdi+0x38] mov r12, qword ptr [rdi+0x60] mov r13, qword ptr [rdi+0x68] mov r14, qword ptr [rdi+0x70] mov r15, qword ptr [rdi+0x78] vmovdqu32 ymm16, ymmword ptr [rdx+r8-0x2*0x20] vinserti64x4 zmm16, zmm16, ymmword ptr [rdx+r12-0x2*0x20], 0x01 vmovdqu32 ymm17, ymmword ptr [rdx+r9-0x2*0x20] vinserti64x4 zmm17, zmm17, ymmword ptr [rdx+r13-0x2*0x20], 0x01 vpunpcklqdq zmm12, zmm16, zmm17 vpunpckhqdq zmm13, zmm16, zmm17 vmovdqu32 ymm18, ymmword ptr [rdx+r10-0x2*0x20] vinserti64x4 zmm18, zmm18, ymmword ptr [rdx+r14-0x2*0x20], 0x01 vmovdqu32 ymm19, ymmword ptr [rdx+r11-0x2*0x20] vinserti64x4 zmm19, zmm19, ymmword ptr [rdx+r15-0x2*0x20], 0x01 vpunpcklqdq zmm14, zmm18, zmm19 vpunpckhqdq zmm15, zmm18, zmm19 vmovdqa32 zmm27, zmmword ptr [INDEX0+rip] vmovdqa32 zmm31, zmmword ptr [INDEX1+rip] vshufps zmm16, zmm8, zmm10, 136 vshufps zmm17, zmm12, zmm14, 136 vmovdqa32 zmm20, zmm16 vpermt2d zmm16, zmm27, zmm17 vpermt2d zmm20, zmm31, zmm17 vshufps zmm17, zmm8, zmm10, 221 vshufps zmm30, zmm12, zmm14, 221 vmovdqa32 zmm21, zmm17 vpermt2d zmm17, zmm27, zmm30 vpermt2d zmm21, zmm31, zmm30 vshufps zmm18, zmm9, zmm11, 136 vshufps zmm8, zmm13, zmm15, 136 vmovdqa32 zmm22, zmm18 vpermt2d zmm18, zmm27, zmm8 vpermt2d zmm22, zmm31, zmm8 vshufps zmm19, zmm9, zmm11, 221 vshufps zmm8, zmm13, zmm15, 221 vmovdqa32 zmm23, zmm19 vpermt2d zmm19, zmm27, zmm8 vpermt2d zmm23, zmm31, zmm8 mov r8, qword ptr [rdi] mov r9, qword ptr [rdi+0x8] mov r10, qword ptr [rdi+0x10] mov r11, qword ptr [rdi+0x18] mov r12, qword ptr [rdi+0x40] mov r13, qword ptr [rdi+0x48] mov r14, qword ptr [rdi+0x50] mov r15, qword ptr [rdi+0x58] vmovdqu32 ymm24, ymmword ptr [r8+rdx-0x1*0x20] vinserti64x4 zmm24, zmm24, ymmword ptr [r12+rdx-0x1*0x20], 0x01 vmovdqu32 ymm25, ymmword ptr [r9+rdx-0x1*0x20] vinserti64x4 zmm25, zmm25, ymmword ptr [r13+rdx-0x1*0x20], 0x01 vpunpcklqdq zmm8, zmm24, zmm25 vpunpckhqdq zmm9, zmm24, zmm25 vmovdqu32 ymm24, ymmword ptr [r10+rdx-0x1*0x20] vinserti64x4 zmm24, zmm24, ymmword ptr [r14+rdx-0x1*0x20], 0x01 vmovdqu32 ymm25, ymmword ptr [r11+rdx-0x1*0x20] vinserti64x4 zmm25, zmm25, ymmword ptr [r15+rdx-0x1*0x20], 0x01 vpunpcklqdq zmm10, zmm24, zmm25 vpunpckhqdq zmm11, zmm24, zmm25 prefetcht0 [r8+rdx+0x80] prefetcht0 [r12+rdx+0x80] prefetcht0 [r9+rdx+0x80] prefetcht0 [r13+rdx+0x80] prefetcht0 [r10+rdx+0x80] prefetcht0 [r14+rdx+0x80] prefetcht0 [r11+rdx+0x80] prefetcht0 [r15+rdx+0x80] mov r8, qword ptr [rdi+0x20] mov r9, qword ptr [rdi+0x28] mov r10, qword ptr [rdi+0x30] mov r11, qword ptr [rdi+0x38] mov r12, qword ptr [rdi+0x60] mov r13, qword ptr [rdi+0x68] mov r14, qword ptr [rdi+0x70] mov r15, qword ptr [rdi+0x78] vmovdqu32 ymm24, ymmword ptr [r8+rdx-0x1*0x20] vinserti64x4 zmm24, zmm24, ymmword ptr [r12+rdx-0x1*0x20], 0x01 vmovdqu32 ymm25, ymmword ptr [r9+rdx-0x1*0x20] vinserti64x4 zmm25, zmm25, ymmword ptr [r13+rdx-0x1*0x20], 0x01 vpunpcklqdq zmm12, zmm24, zmm25 vpunpckhqdq zmm13, zmm24, zmm25 vmovdqu32 ymm24, ymmword ptr [r10+rdx-0x1*0x20] vinserti64x4 zmm24, zmm24, ymmword ptr [r14+rdx-0x1*0x20], 0x01 vmovdqu32 ymm25, ymmword ptr [r11+rdx-0x1*0x20] vinserti64x4 zmm25, zmm25, ymmword ptr [r15+rdx-0x1*0x20], 0x01 vpunpcklqdq zmm14, zmm24, zmm25 vpunpckhqdq zmm15, zmm24, zmm25 prefetcht0 [r8+rdx+0x80] prefetcht0 [r12+rdx+0x80] prefetcht0 [r9+rdx+0x80] prefetcht0 [r13+rdx+0x80] prefetcht0 [r10+rdx+0x80] prefetcht0 [r14+rdx+0x80] prefetcht0 [r11+rdx+0x80] prefetcht0 [r15+rdx+0x80] vshufps zmm24, zmm8, zmm10, 136 vshufps zmm30, zmm12, zmm14, 136 vmovdqa32 zmm28, zmm24 vpermt2d zmm24, zmm27, zmm30 vpermt2d zmm28, zmm31, zmm30 vshufps zmm25, zmm8, zmm10, 221 vshufps zmm30, zmm12, zmm14, 221 vmovdqa32 zmm29, zmm25 vpermt2d zmm25, zmm27, zmm30 vpermt2d zmm29, zmm31, zmm30 vshufps zmm26, zmm9, zmm11, 136 vshufps zmm8, zmm13, zmm15, 136 vmovdqa32 zmm30, zmm26 vpermt2d zmm26, zmm27, zmm8 vpermt2d zmm30, zmm31, zmm8 vshufps zmm8, zmm9, zmm11, 221 vshufps zmm10, zmm13, zmm15, 221 vpermi2d zmm27, zmm8, zmm10 vpermi2d zmm31, zmm8, zmm10 vpbroadcastd zmm8, dword ptr [BLAKE3_IV_0+rip] vpbroadcastd zmm9, dword ptr [BLAKE3_IV_1+rip] vpbroadcastd zmm10, dword ptr [BLAKE3_IV_2+rip] vpbroadcastd zmm11, dword ptr [BLAKE3_IV_3+rip] vmovdqa32 zmm12, zmmword ptr [rsp] vmovdqa32 zmm13, zmmword ptr [rsp+0x1*0x40] vpbroadcastd zmm14, dword ptr [BLAKE3_BLOCK_LEN+rip] vpbroadcastd zmm15, dword ptr [rsp+0x22*0x4] vpaddd zmm0, zmm0, zmm16 vpaddd zmm1, zmm1, zmm18 vpaddd zmm2, zmm2, zmm20 vpaddd zmm3, zmm3, zmm22 vpaddd zmm0, zmm0, zmm4 vpaddd zmm1, zmm1, zmm5 vpaddd zmm2, zmm2, zmm6 vpaddd zmm3, zmm3, zmm7 vpxord zmm12, zmm12, zmm0 vpxord zmm13, zmm13, zmm1 vpxord zmm14, zmm14, zmm2 vpxord zmm15, zmm15, zmm3 vprord zmm12, zmm12, 16 vprord zmm13, zmm13, 16 vprord zmm14, zmm14, 16 vprord zmm15, zmm15, 16 vpaddd zmm8, zmm8, zmm12 vpaddd zmm9, zmm9, zmm13 vpaddd zmm10, zmm10, zmm14 vpaddd zmm11, zmm11, zmm15 vpxord zmm4, zmm4, zmm8 vpxord zmm5, zmm5, zmm9 vpxord zmm6, zmm6, zmm10 vpxord zmm7, zmm7, zmm11 vprord zmm4, zmm4, 12 vprord zmm5, zmm5, 12 vprord zmm6, zmm6, 12 vprord zmm7, zmm7, 12 vpaddd zmm0, zmm0, zmm17 vpaddd zmm1, zmm1, zmm19 vpaddd zmm2, zmm2, zmm21 vpaddd zmm3, zmm3, zmm23 vpaddd zmm0, zmm0, zmm4 vpaddd zmm1, zmm1, zmm5 vpaddd zmm2, zmm2, zmm6 vpaddd zmm3, zmm3, zmm7 vpxord zmm12, zmm12, zmm0 vpxord zmm13, zmm13, zmm1 vpxord zmm14, zmm14, zmm2 vpxord zmm15, zmm15, zmm3 vprord zmm12, zmm12, 8 vprord zmm13, zmm13, 8 vprord zmm14, zmm14, 8 vprord zmm15, zmm15, 8 vpaddd zmm8, zmm8, zmm12 vpaddd zmm9, zmm9, zmm13 vpaddd zmm10, zmm10, zmm14 vpaddd zmm11, zmm11, zmm15 vpxord zmm4, zmm4, zmm8 vpxord zmm5, zmm5, zmm9 vpxord zmm6, zmm6, zmm10 vpxord zmm7, zmm7, zmm11 vprord zmm4, zmm4, 7 vprord zmm5, zmm5, 7 vprord zmm6, zmm6, 7 vprord zmm7, zmm7, 7 vpaddd zmm0, zmm0, zmm24 vpaddd zmm1, zmm1, zmm26 vpaddd zmm2, zmm2, zmm28 vpaddd zmm3, zmm3, zmm30 vpaddd zmm0, zmm0, zmm5 vpaddd zmm1, zmm1, zmm6 vpaddd zmm2, zmm2, zmm7 vpaddd zmm3, zmm3, zmm4 vpxord zmm15, zmm15, zmm0 vpxord zmm12, zmm12, zmm1 vpxord zmm13, zmm13, zmm2 vpxord zmm14, zmm14, zmm3 vprord zmm15, zmm15, 16 vprord zmm12, zmm12, 16 vprord zmm13, zmm13, 16 vprord zmm14, zmm14, 16 vpaddd zmm10, zmm10, zmm15 vpaddd zmm11, zmm11, zmm12 vpaddd zmm8, zmm8, zmm13 vpaddd zmm9, zmm9, zmm14 vpxord zmm5, zmm5, zmm10 vpxord zmm6, zmm6, zmm11 vpxord zmm7, zmm7, zmm8 vpxord zmm4, zmm4, zmm9 vprord zmm5, zmm5, 12 vprord zmm6, zmm6, 12 vprord zmm7, zmm7, 12 vprord zmm4, zmm4, 12 vpaddd zmm0, zmm0, zmm25 vpaddd zmm1, zmm1, zmm27 vpaddd zmm2, zmm2, zmm29 vpaddd zmm3, zmm3, zmm31 vpaddd zmm0, zmm0, zmm5 vpaddd zmm1, zmm1, zmm6 vpaddd zmm2, zmm2, zmm7 vpaddd zmm3, zmm3, zmm4 vpxord zmm15, zmm15, zmm0 vpxord zmm12, zmm12, zmm1 vpxord zmm13, zmm13, zmm2 vpxord zmm14, zmm14, zmm3 vprord zmm15, zmm15, 8 vprord zmm12, zmm12, 8 vprord zmm13, zmm13, 8 vprord zmm14, zmm14, 8 vpaddd zmm10, zmm10, zmm15 vpaddd zmm11, zmm11, zmm12 vpaddd zmm8, zmm8, zmm13 vpaddd zmm9, zmm9, zmm14 vpxord zmm5, zmm5, zmm10 vpxord zmm6, zmm6, zmm11 vpxord zmm7, zmm7, zmm8 vpxord zmm4, zmm4, zmm9 vprord zmm5, zmm5, 7 vprord zmm6, zmm6, 7 vprord zmm7, zmm7, 7 vprord zmm4, zmm4, 7 vpaddd zmm0, zmm0, zmm18 vpaddd zmm1, zmm1, zmm19 vpaddd zmm2, zmm2, zmm23 vpaddd zmm3, zmm3, zmm20 vpaddd zmm0, zmm0, zmm4 vpaddd zmm1, zmm1, zmm5 vpaddd zmm2, zmm2, zmm6 vpaddd zmm3, zmm3, zmm7 vpxord zmm12, zmm12, zmm0 vpxord zmm13, zmm13, zmm1 vpxord zmm14, zmm14, zmm2 vpxord zmm15, zmm15, zmm3 vprord zmm12, zmm12, 16 vprord zmm13, zmm13, 16 vprord zmm14, zmm14, 16 vprord zmm15, zmm15, 16 vpaddd zmm8, zmm8, zmm12 vpaddd zmm9, zmm9, zmm13 vpaddd zmm10, zmm10, zmm14 vpaddd zmm11, zmm11, zmm15 vpxord zmm4, zmm4, zmm8 vpxord zmm5, zmm5, zmm9 vpxord zmm6, zmm6, zmm10 vpxord zmm7, zmm7, zmm11 vprord zmm4, zmm4, 12 vprord zmm5, zmm5, 12 vprord zmm6, zmm6, 12 vprord zmm7, zmm7, 12 vpaddd zmm0, zmm0, zmm22 vpaddd zmm1, zmm1, zmm26 vpaddd zmm2, zmm2, zmm16 vpaddd zmm3, zmm3, zmm29 vpaddd zmm0, zmm0, zmm4 vpaddd zmm1, zmm1, zmm5 vpaddd zmm2, zmm2, zmm6 vpaddd zmm3, zmm3, zmm7 vpxord zmm12, zmm12, zmm0 vpxord zmm13, zmm13, zmm1 vpxord zmm14, zmm14, zmm2 vpxord zmm15, zmm15, zmm3 vprord zmm12, zmm12, 8 vprord zmm13, zmm13, 8 vprord zmm14, zmm14, 8 vprord zmm15, zmm15, 8 vpaddd zmm8, zmm8, zmm12 vpaddd zmm9, zmm9, zmm13 vpaddd zmm10, zmm10, zmm14 vpaddd zmm11, zmm11, zmm15 vpxord zmm4, zmm4, zmm8 vpxord zmm5, zmm5, zmm9 vpxord zmm6, zmm6, zmm10 vpxord zmm7, zmm7, zmm11 vprord zmm4, zmm4, 7 vprord zmm5, zmm5, 7 vprord zmm6, zmm6, 7 vprord zmm7, zmm7, 7 vpaddd zmm0, zmm0, zmm17 vpaddd zmm1, zmm1, zmm28 vpaddd zmm2, zmm2, zmm25 vpaddd zmm3, zmm3, zmm31 vpaddd zmm0, zmm0, zmm5 vpaddd zmm1, zmm1, zmm6 vpaddd zmm2, zmm2, zmm7 vpaddd zmm3, zmm3, zmm4 vpxord zmm15, zmm15, zmm0 vpxord zmm12, zmm12, zmm1 vpxord zmm13, zmm13, zmm2 vpxord zmm14, zmm14, zmm3 vprord zmm15, zmm15, 16 vprord zmm12, zmm12, 16 vprord zmm13, zmm13, 16 vprord zmm14, zmm14, 16 vpaddd zmm10, zmm10, zmm15 vpaddd zmm11, zmm11, zmm12 vpaddd zmm8, zmm8, zmm13 vpaddd zmm9, zmm9, zmm14 vpxord zmm5, zmm5, zmm10 vpxord zmm6, zmm6, zmm11 vpxord zmm7, zmm7, zmm8 vpxord zmm4, zmm4, zmm9 vprord zmm5, zmm5, 12 vprord zmm6, zmm6, 12 vprord zmm7, zmm7, 12 vprord zmm4, zmm4, 12 vpaddd zmm0, zmm0, zmm27 vpaddd zmm1, zmm1, zmm21 vpaddd zmm2, zmm2, zmm30 vpaddd zmm3, zmm3, zmm24 vpaddd zmm0, zmm0, zmm5 vpaddd zmm1, zmm1, zmm6 vpaddd zmm2, zmm2, zmm7 vpaddd zmm3, zmm3, zmm4 vpxord zmm15, zmm15, zmm0 vpxord zmm12, zmm12, zmm1 vpxord zmm13, zmm13, zmm2 vpxord zmm14, zmm14, zmm3 vprord zmm15, zmm15, 8 vprord zmm12, zmm12, 8 vprord zmm13, zmm13, 8 vprord zmm14, zmm14, 8 vpaddd zmm10, zmm10, zmm15 vpaddd zmm11, zmm11, zmm12 vpaddd zmm8, zmm8, zmm13 vpaddd zmm9, zmm9, zmm14 vpxord zmm5, zmm5, zmm10 vpxord zmm6, zmm6, zmm11 vpxord zmm7, zmm7, zmm8 vpxord zmm4, zmm4, zmm9 vprord zmm5, zmm5, 7 vprord zmm6, zmm6, 7 vprord zmm7, zmm7, 7 vprord zmm4, zmm4, 7 vpaddd zmm0, zmm0, zmm19 vpaddd zmm1, zmm1, zmm26 vpaddd zmm2, zmm2, zmm29 vpaddd zmm3, zmm3, zmm23 vpaddd zmm0, zmm0, zmm4 vpaddd zmm1, zmm1, zmm5 vpaddd zmm2, zmm2, zmm6 vpaddd zmm3, zmm3, zmm7 vpxord zmm12, zmm12, zmm0 vpxord zmm13, zmm13, zmm1 vpxord zmm14, zmm14, zmm2 vpxord zmm15, zmm15, zmm3 vprord zmm12, zmm12, 16 vprord zmm13, zmm13, 16 vprord zmm14, zmm14, 16 vprord zmm15, zmm15, 16 vpaddd zmm8, zmm8, zmm12 vpaddd zmm9, zmm9, zmm13 vpaddd zmm10, zmm10, zmm14 vpaddd zmm11, zmm11, zmm15 vpxord zmm4, zmm4, zmm8 vpxord zmm5, zmm5, zmm9 vpxord zmm6, zmm6, zmm10 vpxord zmm7, zmm7, zmm11 vprord zmm4, zmm4, 12 vprord zmm5, zmm5, 12 vprord zmm6, zmm6, 12 vprord zmm7, zmm7, 12 vpaddd zmm0, zmm0, zmm20 vpaddd zmm1, zmm1, zmm28 vpaddd zmm2, zmm2, zmm18 vpaddd zmm3, zmm3, zmm30 vpaddd zmm0, zmm0, zmm4 vpaddd zmm1, zmm1, zmm5 vpaddd zmm2, zmm2, zmm6 vpaddd zmm3, zmm3, zmm7 vpxord zmm12, zmm12, zmm0 vpxord zmm13, zmm13, zmm1 vpxord zmm14, zmm14, zmm2 vpxord zmm15, zmm15, zmm3 vprord zmm12, zmm12, 8 vprord zmm13, zmm13, 8 vprord zmm14, zmm14, 8 vprord zmm15, zmm15, 8 vpaddd zmm8, zmm8, zmm12 vpaddd zmm9, zmm9, zmm13 vpaddd zmm10, zmm10, zmm14 vpaddd zmm11, zmm11, zmm15 vpxord zmm4, zmm4, zmm8 vpxord zmm5, zmm5, zmm9 vpxord zmm6, zmm6, zmm10 vpxord zmm7, zmm7, zmm11 vprord zmm4, zmm4, 7 vprord zmm5, zmm5, 7 vprord zmm6, zmm6, 7 vprord zmm7, zmm7, 7 vpaddd zmm0, zmm0, zmm22 vpaddd zmm1, zmm1, zmm25 vpaddd zmm2, zmm2, zmm27 vpaddd zmm3, zmm3, zmm24 vpaddd zmm0, zmm0, zmm5 vpaddd zmm1, zmm1, zmm6 vpaddd zmm2, zmm2, zmm7 vpaddd zmm3, zmm3, zmm4 vpxord zmm15, zmm15, zmm0 vpxord zmm12, zmm12, zmm1 vpxord zmm13, zmm13, zmm2 vpxord zmm14, zmm14, zmm3 vprord zmm15, zmm15, 16 vprord zmm12, zmm12, 16 vprord zmm13, zmm13, 16 vprord zmm14, zmm14, 16 vpaddd zmm10, zmm10, zmm15 vpaddd zmm11, zmm11, zmm12 vpaddd zmm8, zmm8, zmm13 vpaddd zmm9, zmm9, zmm14 vpxord zmm5, zmm5, zmm10 vpxord zmm6, zmm6, zmm11 vpxord zmm7, zmm7, zmm8 vpxord zmm4, zmm4, zmm9 vprord zmm5, zmm5, 12 vprord zmm6, zmm6, 12 vprord zmm7, zmm7, 12 vprord zmm4, zmm4, 12 vpaddd zmm0, zmm0, zmm21 vpaddd zmm1, zmm1, zmm16 vpaddd zmm2, zmm2, zmm31 vpaddd zmm3, zmm3, zmm17 vpaddd zmm0, zmm0, zmm5 vpaddd zmm1, zmm1, zmm6 vpaddd zmm2, zmm2, zmm7 vpaddd zmm3, zmm3, zmm4 vpxord zmm15, zmm15, zmm0 vpxord zmm12, zmm12, zmm1 vpxord zmm13, zmm13, zmm2 vpxord zmm14, zmm14, zmm3 vprord zmm15, zmm15, 8 vprord zmm12, zmm12, 8 vprord zmm13, zmm13, 8 vprord zmm14, zmm14, 8 vpaddd zmm10, zmm10, zmm15 vpaddd zmm11, zmm11, zmm12 vpaddd zmm8, zmm8, zmm13 vpaddd zmm9, zmm9, zmm14 vpxord zmm5, zmm5, zmm10 vpxord zmm6, zmm6, zmm11 vpxord zmm7, zmm7, zmm8 vpxord zmm4, zmm4, zmm9 vprord zmm5, zmm5, 7 vprord zmm6, zmm6, 7 vprord zmm7, zmm7, 7 vprord zmm4, zmm4, 7 vpaddd zmm0, zmm0, zmm26 vpaddd zmm1, zmm1, zmm28 vpaddd zmm2, zmm2, zmm30 vpaddd zmm3, zmm3, zmm29 vpaddd zmm0, zmm0, zmm4 vpaddd zmm1, zmm1, zmm5 vpaddd zmm2, zmm2, zmm6 vpaddd zmm3, zmm3, zmm7 vpxord zmm12, zmm12, zmm0 vpxord zmm13, zmm13, zmm1 vpxord zmm14, zmm14, zmm2 vpxord zmm15, zmm15, zmm3 vprord zmm12, zmm12, 16 vprord zmm13, zmm13, 16 vprord zmm14, zmm14, 16 vprord zmm15, zmm15, 16 vpaddd zmm8, zmm8, zmm12 vpaddd zmm9, zmm9, zmm13 vpaddd zmm10, zmm10, zmm14 vpaddd zmm11, zmm11, zmm15 vpxord zmm4, zmm4, zmm8 vpxord zmm5, zmm5, zmm9 vpxord zmm6, zmm6, zmm10 vpxord zmm7, zmm7, zmm11 vprord zmm4, zmm4, 12 vprord zmm5, zmm5, 12 vprord zmm6, zmm6, 12 vprord zmm7, zmm7, 12 vpaddd zmm0, zmm0, zmm23 vpaddd zmm1, zmm1, zmm25 vpaddd zmm2, zmm2, zmm19 vpaddd zmm3, zmm3, zmm31 vpaddd zmm0, zmm0, zmm4 vpaddd zmm1, zmm1, zmm5 vpaddd zmm2, zmm2, zmm6 vpaddd zmm3, zmm3, zmm7 vpxord zmm12, zmm12, zmm0 vpxord zmm13, zmm13, zmm1 vpxord zmm14, zmm14, zmm2 vpxord zmm15, zmm15, zmm3 vprord zmm12, zmm12, 8 vprord zmm13, zmm13, 8 vprord zmm14, zmm14, 8 vprord zmm15, zmm15, 8 vpaddd zmm8, zmm8, zmm12 vpaddd zmm9, zmm9, zmm13 vpaddd zmm10, zmm10, zmm14 vpaddd zmm11, zmm11, zmm15 vpxord zmm4, zmm4, zmm8 vpxord zmm5, zmm5, zmm9 vpxord zmm6, zmm6, zmm10 vpxord zmm7, zmm7, zmm11 vprord zmm4, zmm4, 7 vprord zmm5, zmm5, 7 vprord zmm6, zmm6, 7 vprord zmm7, zmm7, 7 vpaddd zmm0, zmm0, zmm20 vpaddd zmm1, zmm1, zmm27 vpaddd zmm2, zmm2, zmm21 vpaddd zmm3, zmm3, zmm17 vpaddd zmm0, zmm0, zmm5 vpaddd zmm1, zmm1, zmm6 vpaddd zmm2, zmm2, zmm7 vpaddd zmm3, zmm3, zmm4 vpxord zmm15, zmm15, zmm0 vpxord zmm12, zmm12, zmm1 vpxord zmm13, zmm13, zmm2 vpxord zmm14, zmm14, zmm3 vprord zmm15, zmm15, 16 vprord zmm12, zmm12, 16 vprord zmm13, zmm13, 16 vprord zmm14, zmm14, 16 vpaddd zmm10, zmm10, zmm15 vpaddd zmm11, zmm11, zmm12 vpaddd zmm8, zmm8, zmm13 vpaddd zmm9, zmm9, zmm14 vpxord zmm5, zmm5, zmm10 vpxord zmm6, zmm6, zmm11 vpxord zmm7, zmm7, zmm8 vpxord zmm4, zmm4, zmm9 vprord zmm5, zmm5, 12 vprord zmm6, zmm6, 12 vprord zmm7, zmm7, 12 vprord zmm4, zmm4, 12 vpaddd zmm0, zmm0, zmm16 vpaddd zmm1, zmm1, zmm18 vpaddd zmm2, zmm2, zmm24 vpaddd zmm3, zmm3, zmm22 vpaddd zmm0, zmm0, zmm5 vpaddd zmm1, zmm1, zmm6 vpaddd zmm2, zmm2, zmm7 vpaddd zmm3, zmm3, zmm4 vpxord zmm15, zmm15, zmm0 vpxord zmm12, zmm12, zmm1 vpxord zmm13, zmm13, zmm2 vpxord zmm14, zmm14, zmm3 vprord zmm15, zmm15, 8 vprord zmm12, zmm12, 8 vprord zmm13, zmm13, 8 vprord zmm14, zmm14, 8 vpaddd zmm10, zmm10, zmm15 vpaddd zmm11, zmm11, zmm12 vpaddd zmm8, zmm8, zmm13 vpaddd zmm9, zmm9, zmm14 vpxord zmm5, zmm5, zmm10 vpxord zmm6, zmm6, zmm11 vpxord zmm7, zmm7, zmm8 vpxord zmm4, zmm4, zmm9 vprord zmm5, zmm5, 7 vprord zmm6, zmm6, 7 vprord zmm7, zmm7, 7 vprord zmm4, zmm4, 7 vpaddd zmm0, zmm0, zmm28 vpaddd zmm1, zmm1, zmm25 vpaddd zmm2, zmm2, zmm31 vpaddd zmm3, zmm3, zmm30 vpaddd zmm0, zmm0, zmm4 vpaddd zmm1, zmm1, zmm5 vpaddd zmm2, zmm2, zmm6 vpaddd zmm3, zmm3, zmm7 vpxord zmm12, zmm12, zmm0 vpxord zmm13, zmm13, zmm1 vpxord zmm14, zmm14, zmm2 vpxord zmm15, zmm15, zmm3 vprord zmm12, zmm12, 16 vprord zmm13, zmm13, 16 vprord zmm14, zmm14, 16 vprord zmm15, zmm15, 16 vpaddd zmm8, zmm8, zmm12 vpaddd zmm9, zmm9, zmm13 vpaddd zmm10, zmm10, zmm14 vpaddd zmm11, zmm11, zmm15 vpxord zmm4, zmm4, zmm8 vpxord zmm5, zmm5, zmm9 vpxord zmm6, zmm6, zmm10 vpxord zmm7, zmm7, zmm11 vprord zmm4, zmm4, 12 vprord zmm5, zmm5, 12 vprord zmm6, zmm6, 12 vprord zmm7, zmm7, 12 vpaddd zmm0, zmm0, zmm29 vpaddd zmm1, zmm1, zmm27 vpaddd zmm2, zmm2, zmm26 vpaddd zmm3, zmm3, zmm24 vpaddd zmm0, zmm0, zmm4 vpaddd zmm1, zmm1, zmm5 vpaddd zmm2, zmm2, zmm6 vpaddd zmm3, zmm3, zmm7 vpxord zmm12, zmm12, zmm0 vpxord zmm13, zmm13, zmm1 vpxord zmm14, zmm14, zmm2 vpxord zmm15, zmm15, zmm3 vprord zmm12, zmm12, 8 vprord zmm13, zmm13, 8 vprord zmm14, zmm14, 8 vprord zmm15, zmm15, 8 vpaddd zmm8, zmm8, zmm12 vpaddd zmm9, zmm9, zmm13 vpaddd zmm10, zmm10, zmm14 vpaddd zmm11, zmm11, zmm15 vpxord zmm4, zmm4, zmm8 vpxord zmm5, zmm5, zmm9 vpxord zmm6, zmm6, zmm10 vpxord zmm7, zmm7, zmm11 vprord zmm4, zmm4, 7 vprord zmm5, zmm5, 7 vprord zmm6, zmm6, 7 vprord zmm7, zmm7, 7 vpaddd zmm0, zmm0, zmm23 vpaddd zmm1, zmm1, zmm21 vpaddd zmm2, zmm2, zmm16 vpaddd zmm3, zmm3, zmm22 vpaddd zmm0, zmm0, zmm5 vpaddd zmm1, zmm1, zmm6 vpaddd zmm2, zmm2, zmm7 vpaddd zmm3, zmm3, zmm4 vpxord zmm15, zmm15, zmm0 vpxord zmm12, zmm12, zmm1 vpxord zmm13, zmm13, zmm2 vpxord zmm14, zmm14, zmm3 vprord zmm15, zmm15, 16 vprord zmm12, zmm12, 16 vprord zmm13, zmm13, 16 vprord zmm14, zmm14, 16 vpaddd zmm10, zmm10, zmm15 vpaddd zmm11, zmm11, zmm12 vpaddd zmm8, zmm8, zmm13 vpaddd zmm9, zmm9, zmm14 vpxord zmm5, zmm5, zmm10 vpxord zmm6, zmm6, zmm11 vpxord zmm7, zmm7, zmm8 vpxord zmm4, zmm4, zmm9 vprord zmm5, zmm5, 12 vprord zmm6, zmm6, 12 vprord zmm7, zmm7, 12 vprord zmm4, zmm4, 12 vpaddd zmm0, zmm0, zmm18 vpaddd zmm1, zmm1, zmm19 vpaddd zmm2, zmm2, zmm17 vpaddd zmm3, zmm3, zmm20 vpaddd zmm0, zmm0, zmm5 vpaddd zmm1, zmm1, zmm6 vpaddd zmm2, zmm2, zmm7 vpaddd zmm3, zmm3, zmm4 vpxord zmm15, zmm15, zmm0 vpxord zmm12, zmm12, zmm1 vpxord zmm13, zmm13, zmm2 vpxord zmm14, zmm14, zmm3 vprord zmm15, zmm15, 8 vprord zmm12, zmm12, 8 vprord zmm13, zmm13, 8 vprord zmm14, zmm14, 8 vpaddd zmm10, zmm10, zmm15 vpaddd zmm11, zmm11, zmm12 vpaddd zmm8, zmm8, zmm13 vpaddd zmm9, zmm9, zmm14 vpxord zmm5, zmm5, zmm10 vpxord zmm6, zmm6, zmm11 vpxord zmm7, zmm7, zmm8 vpxord zmm4, zmm4, zmm9 vprord zmm5, zmm5, 7 vprord zmm6, zmm6, 7 vprord zmm7, zmm7, 7 vprord zmm4, zmm4, 7 vpaddd zmm0, zmm0, zmm25 vpaddd zmm1, zmm1, zmm27 vpaddd zmm2, zmm2, zmm24 vpaddd zmm3, zmm3, zmm31 vpaddd zmm0, zmm0, zmm4 vpaddd zmm1, zmm1, zmm5 vpaddd zmm2, zmm2, zmm6 vpaddd zmm3, zmm3, zmm7 vpxord zmm12, zmm12, zmm0 vpxord zmm13, zmm13, zmm1 vpxord zmm14, zmm14, zmm2 vpxord zmm15, zmm15, zmm3 vprord zmm12, zmm12, 16 vprord zmm13, zmm13, 16 vprord zmm14, zmm14, 16 vprord zmm15, zmm15, 16 vpaddd zmm8, zmm8, zmm12 vpaddd zmm9, zmm9, zmm13 vpaddd zmm10, zmm10, zmm14 vpaddd zmm11, zmm11, zmm15 vpxord zmm4, zmm4, zmm8 vpxord zmm5, zmm5, zmm9 vpxord zmm6, zmm6, zmm10 vpxord zmm7, zmm7, zmm11 vprord zmm4, zmm4, 12 vprord zmm5, zmm5, 12 vprord zmm6, zmm6, 12 vprord zmm7, zmm7, 12 vpaddd zmm0, zmm0, zmm30 vpaddd zmm1, zmm1, zmm21 vpaddd zmm2, zmm2, zmm28 vpaddd zmm3, zmm3, zmm17 vpaddd zmm0, zmm0, zmm4 vpaddd zmm1, zmm1, zmm5 vpaddd zmm2, zmm2, zmm6 vpaddd zmm3, zmm3, zmm7 vpxord zmm12, zmm12, zmm0 vpxord zmm13, zmm13, zmm1 vpxord zmm14, zmm14, zmm2 vpxord zmm15, zmm15, zmm3 vprord zmm12, zmm12, 8 vprord zmm13, zmm13, 8 vprord zmm14, zmm14, 8 vprord zmm15, zmm15, 8 vpaddd zmm8, zmm8, zmm12 vpaddd zmm9, zmm9, zmm13 vpaddd zmm10, zmm10, zmm14 vpaddd zmm11, zmm11, zmm15 vpxord zmm4, zmm4, zmm8 vpxord zmm5, zmm5, zmm9 vpxord zmm6, zmm6, zmm10 vpxord zmm7, zmm7, zmm11 vprord zmm4, zmm4, 7 vprord zmm5, zmm5, 7 vprord zmm6, zmm6, 7 vprord zmm7, zmm7, 7 vpaddd zmm0, zmm0, zmm29 vpaddd zmm1, zmm1, zmm16 vpaddd zmm2, zmm2, zmm18 vpaddd zmm3, zmm3, zmm20 vpaddd zmm0, zmm0, zmm5 vpaddd zmm1, zmm1, zmm6 vpaddd zmm2, zmm2, zmm7 vpaddd zmm3, zmm3, zmm4 vpxord zmm15, zmm15, zmm0 vpxord zmm12, zmm12, zmm1 vpxord zmm13, zmm13, zmm2 vpxord zmm14, zmm14, zmm3 vprord zmm15, zmm15, 16 vprord zmm12, zmm12, 16 vprord zmm13, zmm13, 16 vprord zmm14, zmm14, 16 vpaddd zmm10, zmm10, zmm15 vpaddd zmm11, zmm11, zmm12 vpaddd zmm8, zmm8, zmm13 vpaddd zmm9, zmm9, zmm14 vpxord zmm5, zmm5, zmm10 vpxord zmm6, zmm6, zmm11 vpxord zmm7, zmm7, zmm8 vpxord zmm4, zmm4, zmm9 vprord zmm5, zmm5, 12 vprord zmm6, zmm6, 12 vprord zmm7, zmm7, 12 vprord zmm4, zmm4, 12 vpaddd zmm0, zmm0, zmm19 vpaddd zmm1, zmm1, zmm26 vpaddd zmm2, zmm2, zmm22 vpaddd zmm3, zmm3, zmm23 vpaddd zmm0, zmm0, zmm5 vpaddd zmm1, zmm1, zmm6 vpaddd zmm2, zmm2, zmm7 vpaddd zmm3, zmm3, zmm4 vpxord zmm15, zmm15, zmm0 vpxord zmm12, zmm12, zmm1 vpxord zmm13, zmm13, zmm2 vpxord zmm14, zmm14, zmm3 vprord zmm15, zmm15, 8 vprord zmm12, zmm12, 8 vprord zmm13, zmm13, 8 vprord zmm14, zmm14, 8 vpaddd zmm10, zmm10, zmm15 vpaddd zmm11, zmm11, zmm12 vpaddd zmm8, zmm8, zmm13 vpaddd zmm9, zmm9, zmm14 vpxord zmm5, zmm5, zmm10 vpxord zmm6, zmm6, zmm11 vpxord zmm7, zmm7, zmm8 vpxord zmm4, zmm4, zmm9 vprord zmm5, zmm5, 7 vprord zmm6, zmm6, 7 vprord zmm7, zmm7, 7 vprord zmm4, zmm4, 7 vpaddd zmm0, zmm0, zmm27 vpaddd zmm1, zmm1, zmm21 vpaddd zmm2, zmm2, zmm17 vpaddd zmm3, zmm3, zmm24 vpaddd zmm0, zmm0, zmm4 vpaddd zmm1, zmm1, zmm5 vpaddd zmm2, zmm2, zmm6 vpaddd zmm3, zmm3, zmm7 vpxord zmm12, zmm12, zmm0 vpxord zmm13, zmm13, zmm1 vpxord zmm14, zmm14, zmm2 vpxord zmm15, zmm15, zmm3 vprord zmm12, zmm12, 16 vprord zmm13, zmm13, 16 vprord zmm14, zmm14, 16 vprord zmm15, zmm15, 16 vpaddd zmm8, zmm8, zmm12 vpaddd zmm9, zmm9, zmm13 vpaddd zmm10, zmm10, zmm14 vpaddd zmm11, zmm11, zmm15 vpxord zmm4, zmm4, zmm8 vpxord zmm5, zmm5, zmm9 vpxord zmm6, zmm6, zmm10 vpxord zmm7, zmm7, zmm11 vprord zmm4, zmm4, 12 vprord zmm5, zmm5, 12 vprord zmm6, zmm6, 12 vprord zmm7, zmm7, 12 vpaddd zmm0, zmm0, zmm31 vpaddd zmm1, zmm1, zmm16 vpaddd zmm2, zmm2, zmm25 vpaddd zmm3, zmm3, zmm22 vpaddd zmm0, zmm0, zmm4 vpaddd zmm1, zmm1, zmm5 vpaddd zmm2, zmm2, zmm6 vpaddd zmm3, zmm3, zmm7 vpxord zmm12, zmm12, zmm0 vpxord zmm13, zmm13, zmm1 vpxord zmm14, zmm14, zmm2 vpxord zmm15, zmm15, zmm3 vprord zmm12, zmm12, 8 vprord zmm13, zmm13, 8 vprord zmm14, zmm14, 8 vprord zmm15, zmm15, 8 vpaddd zmm8, zmm8, zmm12 vpaddd zmm9, zmm9, zmm13 vpaddd zmm10, zmm10, zmm14 vpaddd zmm11, zmm11, zmm15 vpxord zmm4, zmm4, zmm8 vpxord zmm5, zmm5, zmm9 vpxord zmm6, zmm6, zmm10 vpxord zmm7, zmm7, zmm11 vprord zmm4, zmm4, 7 vprord zmm5, zmm5, 7 vprord zmm6, zmm6, 7 vprord zmm7, zmm7, 7 vpaddd zmm0, zmm0, zmm30 vpaddd zmm1, zmm1, zmm18 vpaddd zmm2, zmm2, zmm19 vpaddd zmm3, zmm3, zmm23 vpaddd zmm0, zmm0, zmm5 vpaddd zmm1, zmm1, zmm6 vpaddd zmm2, zmm2, zmm7 vpaddd zmm3, zmm3, zmm4 vpxord zmm15, zmm15, zmm0 vpxord zmm12, zmm12, zmm1 vpxord zmm13, zmm13, zmm2 vpxord zmm14, zmm14, zmm3 vprord zmm15, zmm15, 16 vprord zmm12, zmm12, 16 vprord zmm13, zmm13, 16 vprord zmm14, zmm14, 16 vpaddd zmm10, zmm10, zmm15 vpaddd zmm11, zmm11, zmm12 vpaddd zmm8, zmm8, zmm13 vpaddd zmm9, zmm9, zmm14 vpxord zmm5, zmm5, zmm10 vpxord zmm6, zmm6, zmm11 vpxord zmm7, zmm7, zmm8 vpxord zmm4, zmm4, zmm9 vprord zmm5, zmm5, 12 vprord zmm6, zmm6, 12 vprord zmm7, zmm7, 12 vprord zmm4, zmm4, 12 vpaddd zmm0, zmm0, zmm26 vpaddd zmm1, zmm1, zmm28 vpaddd zmm2, zmm2, zmm20 vpaddd zmm3, zmm3, zmm29 vpaddd zmm0, zmm0, zmm5 vpaddd zmm1, zmm1, zmm6 vpaddd zmm2, zmm2, zmm7 vpaddd zmm3, zmm3, zmm4 vpxord zmm15, zmm15, zmm0 vpxord zmm12, zmm12, zmm1 vpxord zmm13, zmm13, zmm2 vpxord zmm14, zmm14, zmm3 vprord zmm15, zmm15, 8 vprord zmm12, zmm12, 8 vprord zmm13, zmm13, 8 vprord zmm14, zmm14, 8 vpaddd zmm10, zmm10, zmm15 vpaddd zmm11, zmm11, zmm12 vpaddd zmm8, zmm8, zmm13 vpaddd zmm9, zmm9, zmm14 vpxord zmm5, zmm5, zmm10 vpxord zmm6, zmm6, zmm11 vpxord zmm7, zmm7, zmm8 vpxord zmm4, zmm4, zmm9 vprord zmm5, zmm5, 7 vprord zmm6, zmm6, 7 vprord zmm7, zmm7, 7 vprord zmm4, zmm4, 7 vpxord zmm0, zmm0, zmm8 vpxord zmm1, zmm1, zmm9 vpxord zmm2, zmm2, zmm10 vpxord zmm3, zmm3, zmm11 vpxord zmm4, zmm4, zmm12 vpxord zmm5, zmm5, zmm13 vpxord zmm6, zmm6, zmm14 vpxord zmm7, zmm7, zmm15 movzx eax, byte ptr [rbp+0x78] jne 9b mov rbx, qword ptr [rbp+0x90] vpunpckldq zmm16, zmm0, zmm1 vpunpckhdq zmm17, zmm0, zmm1 vpunpckldq zmm18, zmm2, zmm3 vpunpckhdq zmm19, zmm2, zmm3 vpunpckldq zmm20, zmm4, zmm5 vpunpckhdq zmm21, zmm4, zmm5 vpunpckldq zmm22, zmm6, zmm7 vpunpckhdq zmm23, zmm6, zmm7 vpunpcklqdq zmm0, zmm16, zmm18 vpunpckhqdq zmm1, zmm16, zmm18 vpunpcklqdq zmm2, zmm17, zmm19 vpunpckhqdq zmm3, zmm17, zmm19 vpunpcklqdq zmm4, zmm20, zmm22 vpunpckhqdq zmm5, zmm20, zmm22 vpunpcklqdq zmm6, zmm21, zmm23 vpunpckhqdq zmm7, zmm21, zmm23 vshufi32x4 zmm16, zmm0, zmm4, 0x88 vshufi32x4 zmm17, zmm1, zmm5, 0x88 vshufi32x4 zmm18, zmm2, zmm6, 0x88 vshufi32x4 zmm19, zmm3, zmm7, 0x88 vshufi32x4 zmm20, zmm0, zmm4, 0xDD vshufi32x4 zmm21, zmm1, zmm5, 0xDD vshufi32x4 zmm22, zmm2, zmm6, 0xDD vshufi32x4 zmm23, zmm3, zmm7, 0xDD vshufi32x4 zmm0, zmm16, zmm17, 0x88 vshufi32x4 zmm1, zmm18, zmm19, 0x88 vshufi32x4 zmm2, zmm20, zmm21, 0x88 vshufi32x4 zmm3, zmm22, zmm23, 0x88 vshufi32x4 zmm4, zmm16, zmm17, 0xDD vshufi32x4 zmm5, zmm18, zmm19, 0xDD vshufi32x4 zmm6, zmm20, zmm21, 0xDD vshufi32x4 zmm7, zmm22, zmm23, 0xDD vmovdqu32 zmmword ptr [rbx], zmm0 vmovdqu32 zmmword ptr [rbx+0x1*0x40], zmm1 vmovdqu32 zmmword ptr [rbx+0x2*0x40], zmm2 vmovdqu32 zmmword ptr [rbx+0x3*0x40], zmm3 vmovdqu32 zmmword ptr [rbx+0x4*0x40], zmm4 vmovdqu32 zmmword ptr [rbx+0x5*0x40], zmm5 vmovdqu32 zmmword ptr [rbx+0x6*0x40], zmm6 vmovdqu32 zmmword ptr [rbx+0x7*0x40], zmm7 vmovdqa32 zmm0, zmmword ptr [rsp] vmovdqa32 zmm1, zmmword ptr [rsp+0x1*0x40] vmovdqa32 zmm2, zmm0 vpaddd zmm2{k1}, zmm0, dword ptr [ADD16+rip] {1to16} vpcmpltud k2, zmm2, zmm0 vpaddd zmm1 {k2}, zmm1, dword ptr [ADD1+rip] {1to16} vmovdqa32 zmmword ptr [rsp], zmm2 vmovdqa32 zmmword ptr [rsp+0x1*0x40], zmm1 add rdi, 128 add rbx, 512 mov qword ptr [rbp+0x90], rbx sub rsi, 16 cmp rsi, 16 jnc 2b test rsi, rsi jne 3f 4: vzeroupper vmovdqa xmm6, xmmword ptr [rsp+0x90] vmovdqa xmm7, xmmword ptr [rsp+0xA0] vmovdqa xmm8, xmmword ptr [rsp+0xB0] vmovdqa xmm9, xmmword ptr [rsp+0xC0] vmovdqa xmm10, xmmword ptr [rsp+0xD0] vmovdqa xmm11, xmmword ptr [rsp+0xE0] vmovdqa xmm12, xmmword ptr [rsp+0xF0] vmovdqa xmm13, xmmword ptr [rsp+0x100] vmovdqa xmm14, xmmword ptr [rsp+0x110] vmovdqa xmm15, xmmword ptr [rsp+0x120] mov rsp, rbp pop rbp pop rbx pop rsi pop rdi pop r12 pop r13 pop r14 pop r15 ret .p2align 6 3: test esi, 0x8 je 3f vpbroadcastd ymm0, dword ptr [rcx] vpbroadcastd ymm1, dword ptr [rcx+0x4] vpbroadcastd ymm2, dword ptr [rcx+0x8] vpbroadcastd ymm3, dword ptr [rcx+0xC] vpbroadcastd ymm4, dword ptr [rcx+0x10] vpbroadcastd ymm5, dword ptr [rcx+0x14] vpbroadcastd ymm6, dword ptr [rcx+0x18] vpbroadcastd ymm7, dword ptr [rcx+0x1C] mov r8, qword ptr [rdi] mov r9, qword ptr [rdi+0x8] mov r10, qword ptr [rdi+0x10] mov r11, qword ptr [rdi+0x18] mov r12, qword ptr [rdi+0x20] mov r13, qword ptr [rdi+0x28] mov r14, qword ptr [rdi+0x30] mov r15, qword ptr [rdi+0x38] movzx eax, byte ptr [rbp+0x78] movzx ebx, byte ptr [rbp+0x80] or eax, ebx xor edx, edx 2: movzx ebx, byte ptr [rbp+0x88] or ebx, eax add rdx, 64 cmp rdx, qword ptr [rsp+0x80] cmove eax, ebx mov dword ptr [rsp+0x88], eax vmovups xmm8, xmmword ptr [r8+rdx-0x40] vinsertf128 ymm8, ymm8, xmmword ptr [r12+rdx-0x40], 0x01 vmovups xmm9, xmmword ptr [r9+rdx-0x40] vinsertf128 ymm9, ymm9, xmmword ptr [r13+rdx-0x40], 0x01 vunpcklpd ymm12, ymm8, ymm9 vunpckhpd ymm13, ymm8, ymm9 vmovups xmm10, xmmword ptr [r10+rdx-0x40] vinsertf128 ymm10, ymm10, xmmword ptr [r14+rdx-0x40], 0x01 vmovups xmm11, xmmword ptr [r11+rdx-0x40] vinsertf128 ymm11, ymm11, xmmword ptr [r15+rdx-0x40], 0x01 vunpcklpd ymm14, ymm10, ymm11 vunpckhpd ymm15, ymm10, ymm11 vshufps ymm16, ymm12, ymm14, 136 vshufps ymm17, ymm12, ymm14, 221 vshufps ymm18, ymm13, ymm15, 136 vshufps ymm19, ymm13, ymm15, 221 vmovups xmm8, xmmword ptr [r8+rdx-0x30] vinsertf128 ymm8, ymm8, xmmword ptr [r12+rdx-0x30], 0x01 vmovups xmm9, xmmword ptr [r9+rdx-0x30] vinsertf128 ymm9, ymm9, xmmword ptr [r13+rdx-0x30], 0x01 vunpcklpd ymm12, ymm8, ymm9 vunpckhpd ymm13, ymm8, ymm9 vmovups xmm10, xmmword ptr [r10+rdx-0x30] vinsertf128 ymm10, ymm10, xmmword ptr [r14+rdx-0x30], 0x01 vmovups xmm11, xmmword ptr [r11+rdx-0x30] vinsertf128 ymm11, ymm11, xmmword ptr [r15+rdx-0x30], 0x01 vunpcklpd ymm14, ymm10, ymm11 vunpckhpd ymm15, ymm10, ymm11 vshufps ymm20, ymm12, ymm14, 136 vshufps ymm21, ymm12, ymm14, 221 vshufps ymm22, ymm13, ymm15, 136 vshufps ymm23, ymm13, ymm15, 221 vmovups xmm8, xmmword ptr [r8+rdx-0x20] vinsertf128 ymm8, ymm8, xmmword ptr [r12+rdx-0x20], 0x01 vmovups xmm9, xmmword ptr [r9+rdx-0x20] vinsertf128 ymm9, ymm9, xmmword ptr [r13+rdx-0x20], 0x01 vunpcklpd ymm12, ymm8, ymm9 vunpckhpd ymm13, ymm8, ymm9 vmovups xmm10, xmmword ptr [r10+rdx-0x20] vinsertf128 ymm10, ymm10, xmmword ptr [r14+rdx-0x20], 0x01 vmovups xmm11, xmmword ptr [r11+rdx-0x20] vinsertf128 ymm11, ymm11, xmmword ptr [r15+rdx-0x20], 0x01 vunpcklpd ymm14, ymm10, ymm11 vunpckhpd ymm15, ymm10, ymm11 vshufps ymm24, ymm12, ymm14, 136 vshufps ymm25, ymm12, ymm14, 221 vshufps ymm26, ymm13, ymm15, 136 vshufps ymm27, ymm13, ymm15, 221 vmovups xmm8, xmmword ptr [r8+rdx-0x10] vinsertf128 ymm8, ymm8, xmmword ptr [r12+rdx-0x10], 0x01 vmovups xmm9, xmmword ptr [r9+rdx-0x10] vinsertf128 ymm9, ymm9, xmmword ptr [r13+rdx-0x10], 0x01 vunpcklpd ymm12, ymm8, ymm9 vunpckhpd ymm13, ymm8, ymm9 vmovups xmm10, xmmword ptr [r10+rdx-0x10] vinsertf128 ymm10, ymm10, xmmword ptr [r14+rdx-0x10], 0x01 vmovups xmm11, xmmword ptr [r11+rdx-0x10] vinsertf128 ymm11, ymm11, xmmword ptr [r15+rdx-0x10], 0x01 vunpcklpd ymm14, ymm10, ymm11 vunpckhpd ymm15, ymm10, ymm11 vshufps ymm28, ymm12, ymm14, 136 vshufps ymm29, ymm12, ymm14, 221 vshufps ymm30, ymm13, ymm15, 136 vshufps ymm31, ymm13, ymm15, 221 vpbroadcastd ymm8, dword ptr [BLAKE3_IV_0+rip] vpbroadcastd ymm9, dword ptr [BLAKE3_IV_1+rip] vpbroadcastd ymm10, dword ptr [BLAKE3_IV_2+rip] vpbroadcastd ymm11, dword ptr [BLAKE3_IV_3+rip] vmovdqa ymm12, ymmword ptr [rsp] vmovdqa ymm13, ymmword ptr [rsp+0x40] vpbroadcastd ymm14, dword ptr [BLAKE3_BLOCK_LEN+rip] vpbroadcastd ymm15, dword ptr [rsp+0x88] vpaddd ymm0, ymm0, ymm16 vpaddd ymm1, ymm1, ymm18 vpaddd ymm2, ymm2, ymm20 vpaddd ymm3, ymm3, ymm22 vpaddd ymm0, ymm0, ymm4 vpaddd ymm1, ymm1, ymm5 vpaddd ymm2, ymm2, ymm6 vpaddd ymm3, ymm3, ymm7 vpxord ymm12, ymm12, ymm0 vpxord ymm13, ymm13, ymm1 vpxord ymm14, ymm14, ymm2 vpxord ymm15, ymm15, ymm3 vprord ymm12, ymm12, 16 vprord ymm13, ymm13, 16 vprord ymm14, ymm14, 16 vprord ymm15, ymm15, 16 vpaddd ymm8, ymm8, ymm12 vpaddd ymm9, ymm9, ymm13 vpaddd ymm10, ymm10, ymm14 vpaddd ymm11, ymm11, ymm15 vpxord ymm4, ymm4, ymm8 vpxord ymm5, ymm5, ymm9 vpxord ymm6, ymm6, ymm10 vpxord ymm7, ymm7, ymm11 vprord ymm4, ymm4, 12 vprord ymm5, ymm5, 12 vprord ymm6, ymm6, 12 vprord ymm7, ymm7, 12 vpaddd ymm0, ymm0, ymm17 vpaddd ymm1, ymm1, ymm19 vpaddd ymm2, ymm2, ymm21 vpaddd ymm3, ymm3, ymm23 vpaddd ymm0, ymm0, ymm4 vpaddd ymm1, ymm1, ymm5 vpaddd ymm2, ymm2, ymm6 vpaddd ymm3, ymm3, ymm7 vpxord ymm12, ymm12, ymm0 vpxord ymm13, ymm13, ymm1 vpxord ymm14, ymm14, ymm2 vpxord ymm15, ymm15, ymm3 vprord ymm12, ymm12, 8 vprord ymm13, ymm13, 8 vprord ymm14, ymm14, 8 vprord ymm15, ymm15, 8 vpaddd ymm8, ymm8, ymm12 vpaddd ymm9, ymm9, ymm13 vpaddd ymm10, ymm10, ymm14 vpaddd ymm11, ymm11, ymm15 vpxord ymm4, ymm4, ymm8 vpxord ymm5, ymm5, ymm9 vpxord ymm6, ymm6, ymm10 vpxord ymm7, ymm7, ymm11 vprord ymm4, ymm4, 7 vprord ymm5, ymm5, 7 vprord ymm6, ymm6, 7 vprord ymm7, ymm7, 7 vpaddd ymm0, ymm0, ymm24 vpaddd ymm1, ymm1, ymm26 vpaddd ymm2, ymm2, ymm28 vpaddd ymm3, ymm3, ymm30 vpaddd ymm0, ymm0, ymm5 vpaddd ymm1, ymm1, ymm6 vpaddd ymm2, ymm2, ymm7 vpaddd ymm3, ymm3, ymm4 vpxord ymm15, ymm15, ymm0 vpxord ymm12, ymm12, ymm1 vpxord ymm13, ymm13, ymm2 vpxord ymm14, ymm14, ymm3 vprord ymm15, ymm15, 16 vprord ymm12, ymm12, 16 vprord ymm13, ymm13, 16 vprord ymm14, ymm14, 16 vpaddd ymm10, ymm10, ymm15 vpaddd ymm11, ymm11, ymm12 vpaddd ymm8, ymm8, ymm13 vpaddd ymm9, ymm9, ymm14 vpxord ymm5, ymm5, ymm10 vpxord ymm6, ymm6, ymm11 vpxord ymm7, ymm7, ymm8 vpxord ymm4, ymm4, ymm9 vprord ymm5, ymm5, 12 vprord ymm6, ymm6, 12 vprord ymm7, ymm7, 12 vprord ymm4, ymm4, 12 vpaddd ymm0, ymm0, ymm25 vpaddd ymm1, ymm1, ymm27 vpaddd ymm2, ymm2, ymm29 vpaddd ymm3, ymm3, ymm31 vpaddd ymm0, ymm0, ymm5 vpaddd ymm1, ymm1, ymm6 vpaddd ymm2, ymm2, ymm7 vpaddd ymm3, ymm3, ymm4 vpxord ymm15, ymm15, ymm0 vpxord ymm12, ymm12, ymm1 vpxord ymm13, ymm13, ymm2 vpxord ymm14, ymm14, ymm3 vprord ymm15, ymm15, 8 vprord ymm12, ymm12, 8 vprord ymm13, ymm13, 8 vprord ymm14, ymm14, 8 vpaddd ymm10, ymm10, ymm15 vpaddd ymm11, ymm11, ymm12 vpaddd ymm8, ymm8, ymm13 vpaddd ymm9, ymm9, ymm14 vpxord ymm5, ymm5, ymm10 vpxord ymm6, ymm6, ymm11 vpxord ymm7, ymm7, ymm8 vpxord ymm4, ymm4, ymm9 vprord ymm5, ymm5, 7 vprord ymm6, ymm6, 7 vprord ymm7, ymm7, 7 vprord ymm4, ymm4, 7 vpaddd ymm0, ymm0, ymm18 vpaddd ymm1, ymm1, ymm19 vpaddd ymm2, ymm2, ymm23 vpaddd ymm3, ymm3, ymm20 vpaddd ymm0, ymm0, ymm4 vpaddd ymm1, ymm1, ymm5 vpaddd ymm2, ymm2, ymm6 vpaddd ymm3, ymm3, ymm7 vpxord ymm12, ymm12, ymm0 vpxord ymm13, ymm13, ymm1 vpxord ymm14, ymm14, ymm2 vpxord ymm15, ymm15, ymm3 vprord ymm12, ymm12, 16 vprord ymm13, ymm13, 16 vprord ymm14, ymm14, 16 vprord ymm15, ymm15, 16 vpaddd ymm8, ymm8, ymm12 vpaddd ymm9, ymm9, ymm13 vpaddd ymm10, ymm10, ymm14 vpaddd ymm11, ymm11, ymm15 vpxord ymm4, ymm4, ymm8 vpxord ymm5, ymm5, ymm9 vpxord ymm6, ymm6, ymm10 vpxord ymm7, ymm7, ymm11 vprord ymm4, ymm4, 12 vprord ymm5, ymm5, 12 vprord ymm6, ymm6, 12 vprord ymm7, ymm7, 12 vpaddd ymm0, ymm0, ymm22 vpaddd ymm1, ymm1, ymm26 vpaddd ymm2, ymm2, ymm16 vpaddd ymm3, ymm3, ymm29 vpaddd ymm0, ymm0, ymm4 vpaddd ymm1, ymm1, ymm5 vpaddd ymm2, ymm2, ymm6 vpaddd ymm3, ymm3, ymm7 vpxord ymm12, ymm12, ymm0 vpxord ymm13, ymm13, ymm1 vpxord ymm14, ymm14, ymm2 vpxord ymm15, ymm15, ymm3 vprord ymm12, ymm12, 8 vprord ymm13, ymm13, 8 vprord ymm14, ymm14, 8 vprord ymm15, ymm15, 8 vpaddd ymm8, ymm8, ymm12 vpaddd ymm9, ymm9, ymm13 vpaddd ymm10, ymm10, ymm14 vpaddd ymm11, ymm11, ymm15 vpxord ymm4, ymm4, ymm8 vpxord ymm5, ymm5, ymm9 vpxord ymm6, ymm6, ymm10 vpxord ymm7, ymm7, ymm11 vprord ymm4, ymm4, 7 vprord ymm5, ymm5, 7 vprord ymm6, ymm6, 7 vprord ymm7, ymm7, 7 vpaddd ymm0, ymm0, ymm17 vpaddd ymm1, ymm1, ymm28 vpaddd ymm2, ymm2, ymm25 vpaddd ymm3, ymm3, ymm31 vpaddd ymm0, ymm0, ymm5 vpaddd ymm1, ymm1, ymm6 vpaddd ymm2, ymm2, ymm7 vpaddd ymm3, ymm3, ymm4 vpxord ymm15, ymm15, ymm0 vpxord ymm12, ymm12, ymm1 vpxord ymm13, ymm13, ymm2 vpxord ymm14, ymm14, ymm3 vprord ymm15, ymm15, 16 vprord ymm12, ymm12, 16 vprord ymm13, ymm13, 16 vprord ymm14, ymm14, 16 vpaddd ymm10, ymm10, ymm15 vpaddd ymm11, ymm11, ymm12 vpaddd ymm8, ymm8, ymm13 vpaddd ymm9, ymm9, ymm14 vpxord ymm5, ymm5, ymm10 vpxord ymm6, ymm6, ymm11 vpxord ymm7, ymm7, ymm8 vpxord ymm4, ymm4, ymm9 vprord ymm5, ymm5, 12 vprord ymm6, ymm6, 12 vprord ymm7, ymm7, 12 vprord ymm4, ymm4, 12 vpaddd ymm0, ymm0, ymm27 vpaddd ymm1, ymm1, ymm21 vpaddd ymm2, ymm2, ymm30 vpaddd ymm3, ymm3, ymm24 vpaddd ymm0, ymm0, ymm5 vpaddd ymm1, ymm1, ymm6 vpaddd ymm2, ymm2, ymm7 vpaddd ymm3, ymm3, ymm4 vpxord ymm15, ymm15, ymm0 vpxord ymm12, ymm12, ymm1 vpxord ymm13, ymm13, ymm2 vpxord ymm14, ymm14, ymm3 vprord ymm15, ymm15, 8 vprord ymm12, ymm12, 8 vprord ymm13, ymm13, 8 vprord ymm14, ymm14, 8 vpaddd ymm10, ymm10, ymm15 vpaddd ymm11, ymm11, ymm12 vpaddd ymm8, ymm8, ymm13 vpaddd ymm9, ymm9, ymm14 vpxord ymm5, ymm5, ymm10 vpxord ymm6, ymm6, ymm11 vpxord ymm7, ymm7, ymm8 vpxord ymm4, ymm4, ymm9 vprord ymm5, ymm5, 7 vprord ymm6, ymm6, 7 vprord ymm7, ymm7, 7 vprord ymm4, ymm4, 7 vpaddd ymm0, ymm0, ymm19 vpaddd ymm1, ymm1, ymm26 vpaddd ymm2, ymm2, ymm29 vpaddd ymm3, ymm3, ymm23 vpaddd ymm0, ymm0, ymm4 vpaddd ymm1, ymm1, ymm5 vpaddd ymm2, ymm2, ymm6 vpaddd ymm3, ymm3, ymm7 vpxord ymm12, ymm12, ymm0 vpxord ymm13, ymm13, ymm1 vpxord ymm14, ymm14, ymm2 vpxord ymm15, ymm15, ymm3 vprord ymm12, ymm12, 16 vprord ymm13, ymm13, 16 vprord ymm14, ymm14, 16 vprord ymm15, ymm15, 16 vpaddd ymm8, ymm8, ymm12 vpaddd ymm9, ymm9, ymm13 vpaddd ymm10, ymm10, ymm14 vpaddd ymm11, ymm11, ymm15 vpxord ymm4, ymm4, ymm8 vpxord ymm5, ymm5, ymm9 vpxord ymm6, ymm6, ymm10 vpxord ymm7, ymm7, ymm11 vprord ymm4, ymm4, 12 vprord ymm5, ymm5, 12 vprord ymm6, ymm6, 12 vprord ymm7, ymm7, 12 vpaddd ymm0, ymm0, ymm20 vpaddd ymm1, ymm1, ymm28 vpaddd ymm2, ymm2, ymm18 vpaddd ymm3, ymm3, ymm30 vpaddd ymm0, ymm0, ymm4 vpaddd ymm1, ymm1, ymm5 vpaddd ymm2, ymm2, ymm6 vpaddd ymm3, ymm3, ymm7 vpxord ymm12, ymm12, ymm0 vpxord ymm13, ymm13, ymm1 vpxord ymm14, ymm14, ymm2 vpxord ymm15, ymm15, ymm3 vprord ymm12, ymm12, 8 vprord ymm13, ymm13, 8 vprord ymm14, ymm14, 8 vprord ymm15, ymm15, 8 vpaddd ymm8, ymm8, ymm12 vpaddd ymm9, ymm9, ymm13 vpaddd ymm10, ymm10, ymm14 vpaddd ymm11, ymm11, ymm15 vpxord ymm4, ymm4, ymm8 vpxord ymm5, ymm5, ymm9 vpxord ymm6, ymm6, ymm10 vpxord ymm7, ymm7, ymm11 vprord ymm4, ymm4, 7 vprord ymm5, ymm5, 7 vprord ymm6, ymm6, 7 vprord ymm7, ymm7, 7 vpaddd ymm0, ymm0, ymm22 vpaddd ymm1, ymm1, ymm25 vpaddd ymm2, ymm2, ymm27 vpaddd ymm3, ymm3, ymm24 vpaddd ymm0, ymm0, ymm5 vpaddd ymm1, ymm1, ymm6 vpaddd ymm2, ymm2, ymm7 vpaddd ymm3, ymm3, ymm4 vpxord ymm15, ymm15, ymm0 vpxord ymm12, ymm12, ymm1 vpxord ymm13, ymm13, ymm2 vpxord ymm14, ymm14, ymm3 vprord ymm15, ymm15, 16 vprord ymm12, ymm12, 16 vprord ymm13, ymm13, 16 vprord ymm14, ymm14, 16 vpaddd ymm10, ymm10, ymm15 vpaddd ymm11, ymm11, ymm12 vpaddd ymm8, ymm8, ymm13 vpaddd ymm9, ymm9, ymm14 vpxord ymm5, ymm5, ymm10 vpxord ymm6, ymm6, ymm11 vpxord ymm7, ymm7, ymm8 vpxord ymm4, ymm4, ymm9 vprord ymm5, ymm5, 12 vprord ymm6, ymm6, 12 vprord ymm7, ymm7, 12 vprord ymm4, ymm4, 12 vpaddd ymm0, ymm0, ymm21 vpaddd ymm1, ymm1, ymm16 vpaddd ymm2, ymm2, ymm31 vpaddd ymm3, ymm3, ymm17 vpaddd ymm0, ymm0, ymm5 vpaddd ymm1, ymm1, ymm6 vpaddd ymm2, ymm2, ymm7 vpaddd ymm3, ymm3, ymm4 vpxord ymm15, ymm15, ymm0 vpxord ymm12, ymm12, ymm1 vpxord ymm13, ymm13, ymm2 vpxord ymm14, ymm14, ymm3 vprord ymm15, ymm15, 8 vprord ymm12, ymm12, 8 vprord ymm13, ymm13, 8 vprord ymm14, ymm14, 8 vpaddd ymm10, ymm10, ymm15 vpaddd ymm11, ymm11, ymm12 vpaddd ymm8, ymm8, ymm13 vpaddd ymm9, ymm9, ymm14 vpxord ymm5, ymm5, ymm10 vpxord ymm6, ymm6, ymm11 vpxord ymm7, ymm7, ymm8 vpxord ymm4, ymm4, ymm9 vprord ymm5, ymm5, 7 vprord ymm6, ymm6, 7 vprord ymm7, ymm7, 7 vprord ymm4, ymm4, 7 vpaddd ymm0, ymm0, ymm26 vpaddd ymm1, ymm1, ymm28 vpaddd ymm2, ymm2, ymm30 vpaddd ymm3, ymm3, ymm29 vpaddd ymm0, ymm0, ymm4 vpaddd ymm1, ymm1, ymm5 vpaddd ymm2, ymm2, ymm6 vpaddd ymm3, ymm3, ymm7 vpxord ymm12, ymm12, ymm0 vpxord ymm13, ymm13, ymm1 vpxord ymm14, ymm14, ymm2 vpxord ymm15, ymm15, ymm3 vprord ymm12, ymm12, 16 vprord ymm13, ymm13, 16 vprord ymm14, ymm14, 16 vprord ymm15, ymm15, 16 vpaddd ymm8, ymm8, ymm12 vpaddd ymm9, ymm9, ymm13 vpaddd ymm10, ymm10, ymm14 vpaddd ymm11, ymm11, ymm15 vpxord ymm4, ymm4, ymm8 vpxord ymm5, ymm5, ymm9 vpxord ymm6, ymm6, ymm10 vpxord ymm7, ymm7, ymm11 vprord ymm4, ymm4, 12 vprord ymm5, ymm5, 12 vprord ymm6, ymm6, 12 vprord ymm7, ymm7, 12 vpaddd ymm0, ymm0, ymm23 vpaddd ymm1, ymm1, ymm25 vpaddd ymm2, ymm2, ymm19 vpaddd ymm3, ymm3, ymm31 vpaddd ymm0, ymm0, ymm4 vpaddd ymm1, ymm1, ymm5 vpaddd ymm2, ymm2, ymm6 vpaddd ymm3, ymm3, ymm7 vpxord ymm12, ymm12, ymm0 vpxord ymm13, ymm13, ymm1 vpxord ymm14, ymm14, ymm2 vpxord ymm15, ymm15, ymm3 vprord ymm12, ymm12, 8 vprord ymm13, ymm13, 8 vprord ymm14, ymm14, 8 vprord ymm15, ymm15, 8 vpaddd ymm8, ymm8, ymm12 vpaddd ymm9, ymm9, ymm13 vpaddd ymm10, ymm10, ymm14 vpaddd ymm11, ymm11, ymm15 vpxord ymm4, ymm4, ymm8 vpxord ymm5, ymm5, ymm9 vpxord ymm6, ymm6, ymm10 vpxord ymm7, ymm7, ymm11 vprord ymm4, ymm4, 7 vprord ymm5, ymm5, 7 vprord ymm6, ymm6, 7 vprord ymm7, ymm7, 7 vpaddd ymm0, ymm0, ymm20 vpaddd ymm1, ymm1, ymm27 vpaddd ymm2, ymm2, ymm21 vpaddd ymm3, ymm3, ymm17 vpaddd ymm0, ymm0, ymm5 vpaddd ymm1, ymm1, ymm6 vpaddd ymm2, ymm2, ymm7 vpaddd ymm3, ymm3, ymm4 vpxord ymm15, ymm15, ymm0 vpxord ymm12, ymm12, ymm1 vpxord ymm13, ymm13, ymm2 vpxord ymm14, ymm14, ymm3 vprord ymm15, ymm15, 16 vprord ymm12, ymm12, 16 vprord ymm13, ymm13, 16 vprord ymm14, ymm14, 16 vpaddd ymm10, ymm10, ymm15 vpaddd ymm11, ymm11, ymm12 vpaddd ymm8, ymm8, ymm13 vpaddd ymm9, ymm9, ymm14 vpxord ymm5, ymm5, ymm10 vpxord ymm6, ymm6, ymm11 vpxord ymm7, ymm7, ymm8 vpxord ymm4, ymm4, ymm9 vprord ymm5, ymm5, 12 vprord ymm6, ymm6, 12 vprord ymm7, ymm7, 12 vprord ymm4, ymm4, 12 vpaddd ymm0, ymm0, ymm16 vpaddd ymm1, ymm1, ymm18 vpaddd ymm2, ymm2, ymm24 vpaddd ymm3, ymm3, ymm22 vpaddd ymm0, ymm0, ymm5 vpaddd ymm1, ymm1, ymm6 vpaddd ymm2, ymm2, ymm7 vpaddd ymm3, ymm3, ymm4 vpxord ymm15, ymm15, ymm0 vpxord ymm12, ymm12, ymm1 vpxord ymm13, ymm13, ymm2 vpxord ymm14, ymm14, ymm3 vprord ymm15, ymm15, 8 vprord ymm12, ymm12, 8 vprord ymm13, ymm13, 8 vprord ymm14, ymm14, 8 vpaddd ymm10, ymm10, ymm15 vpaddd ymm11, ymm11, ymm12 vpaddd ymm8, ymm8, ymm13 vpaddd ymm9, ymm9, ymm14 vpxord ymm5, ymm5, ymm10 vpxord ymm6, ymm6, ymm11 vpxord ymm7, ymm7, ymm8 vpxord ymm4, ymm4, ymm9 vprord ymm5, ymm5, 7 vprord ymm6, ymm6, 7 vprord ymm7, ymm7, 7 vprord ymm4, ymm4, 7 vpaddd ymm0, ymm0, ymm28 vpaddd ymm1, ymm1, ymm25 vpaddd ymm2, ymm2, ymm31 vpaddd ymm3, ymm3, ymm30 vpaddd ymm0, ymm0, ymm4 vpaddd ymm1, ymm1, ymm5 vpaddd ymm2, ymm2, ymm6 vpaddd ymm3, ymm3, ymm7 vpxord ymm12, ymm12, ymm0 vpxord ymm13, ymm13, ymm1 vpxord ymm14, ymm14, ymm2 vpxord ymm15, ymm15, ymm3 vprord ymm12, ymm12, 16 vprord ymm13, ymm13, 16 vprord ymm14, ymm14, 16 vprord ymm15, ymm15, 16 vpaddd ymm8, ymm8, ymm12 vpaddd ymm9, ymm9, ymm13 vpaddd ymm10, ymm10, ymm14 vpaddd ymm11, ymm11, ymm15 vpxord ymm4, ymm4, ymm8 vpxord ymm5, ymm5, ymm9 vpxord ymm6, ymm6, ymm10 vpxord ymm7, ymm7, ymm11 vprord ymm4, ymm4, 12 vprord ymm5, ymm5, 12 vprord ymm6, ymm6, 12 vprord ymm7, ymm7, 12 vpaddd ymm0, ymm0, ymm29 vpaddd ymm1, ymm1, ymm27 vpaddd ymm2, ymm2, ymm26 vpaddd ymm3, ymm3, ymm24 vpaddd ymm0, ymm0, ymm4 vpaddd ymm1, ymm1, ymm5 vpaddd ymm2, ymm2, ymm6 vpaddd ymm3, ymm3, ymm7 vpxord ymm12, ymm12, ymm0 vpxord ymm13, ymm13, ymm1 vpxord ymm14, ymm14, ymm2 vpxord ymm15, ymm15, ymm3 vprord ymm12, ymm12, 8 vprord ymm13, ymm13, 8 vprord ymm14, ymm14, 8 vprord ymm15, ymm15, 8 vpaddd ymm8, ymm8, ymm12 vpaddd ymm9, ymm9, ymm13 vpaddd ymm10, ymm10, ymm14 vpaddd ymm11, ymm11, ymm15 vpxord ymm4, ymm4, ymm8 vpxord ymm5, ymm5, ymm9 vpxord ymm6, ymm6, ymm10 vpxord ymm7, ymm7, ymm11 vprord ymm4, ymm4, 7 vprord ymm5, ymm5, 7 vprord ymm6, ymm6, 7 vprord ymm7, ymm7, 7 vpaddd ymm0, ymm0, ymm23 vpaddd ymm1, ymm1, ymm21 vpaddd ymm2, ymm2, ymm16 vpaddd ymm3, ymm3, ymm22 vpaddd ymm0, ymm0, ymm5 vpaddd ymm1, ymm1, ymm6 vpaddd ymm2, ymm2, ymm7 vpaddd ymm3, ymm3, ymm4 vpxord ymm15, ymm15, ymm0 vpxord ymm12, ymm12, ymm1 vpxord ymm13, ymm13, ymm2 vpxord ymm14, ymm14, ymm3 vprord ymm15, ymm15, 16 vprord ymm12, ymm12, 16 vprord ymm13, ymm13, 16 vprord ymm14, ymm14, 16 vpaddd ymm10, ymm10, ymm15 vpaddd ymm11, ymm11, ymm12 vpaddd ymm8, ymm8, ymm13 vpaddd ymm9, ymm9, ymm14 vpxord ymm5, ymm5, ymm10 vpxord ymm6, ymm6, ymm11 vpxord ymm7, ymm7, ymm8 vpxord ymm4, ymm4, ymm9 vprord ymm5, ymm5, 12 vprord ymm6, ymm6, 12 vprord ymm7, ymm7, 12 vprord ymm4, ymm4, 12 vpaddd ymm0, ymm0, ymm18 vpaddd ymm1, ymm1, ymm19 vpaddd ymm2, ymm2, ymm17 vpaddd ymm3, ymm3, ymm20 vpaddd ymm0, ymm0, ymm5 vpaddd ymm1, ymm1, ymm6 vpaddd ymm2, ymm2, ymm7 vpaddd ymm3, ymm3, ymm4 vpxord ymm15, ymm15, ymm0 vpxord ymm12, ymm12, ymm1 vpxord ymm13, ymm13, ymm2 vpxord ymm14, ymm14, ymm3 vprord ymm15, ymm15, 8 vprord ymm12, ymm12, 8 vprord ymm13, ymm13, 8 vprord ymm14, ymm14, 8 vpaddd ymm10, ymm10, ymm15 vpaddd ymm11, ymm11, ymm12 vpaddd ymm8, ymm8, ymm13 vpaddd ymm9, ymm9, ymm14 vpxord ymm5, ymm5, ymm10 vpxord ymm6, ymm6, ymm11 vpxord ymm7, ymm7, ymm8 vpxord ymm4, ymm4, ymm9 vprord ymm5, ymm5, 7 vprord ymm6, ymm6, 7 vprord ymm7, ymm7, 7 vprord ymm4, ymm4, 7 vpaddd ymm0, ymm0, ymm25 vpaddd ymm1, ymm1, ymm27 vpaddd ymm2, ymm2, ymm24 vpaddd ymm3, ymm3, ymm31 vpaddd ymm0, ymm0, ymm4 vpaddd ymm1, ymm1, ymm5 vpaddd ymm2, ymm2, ymm6 vpaddd ymm3, ymm3, ymm7 vpxord ymm12, ymm12, ymm0 vpxord ymm13, ymm13, ymm1 vpxord ymm14, ymm14, ymm2 vpxord ymm15, ymm15, ymm3 vprord ymm12, ymm12, 16 vprord ymm13, ymm13, 16 vprord ymm14, ymm14, 16 vprord ymm15, ymm15, 16 vpaddd ymm8, ymm8, ymm12 vpaddd ymm9, ymm9, ymm13 vpaddd ymm10, ymm10, ymm14 vpaddd ymm11, ymm11, ymm15 vpxord ymm4, ymm4, ymm8 vpxord ymm5, ymm5, ymm9 vpxord ymm6, ymm6, ymm10 vpxord ymm7, ymm7, ymm11 vprord ymm4, ymm4, 12 vprord ymm5, ymm5, 12 vprord ymm6, ymm6, 12 vprord ymm7, ymm7, 12 vpaddd ymm0, ymm0, ymm30 vpaddd ymm1, ymm1, ymm21 vpaddd ymm2, ymm2, ymm28 vpaddd ymm3, ymm3, ymm17 vpaddd ymm0, ymm0, ymm4 vpaddd ymm1, ymm1, ymm5 vpaddd ymm2, ymm2, ymm6 vpaddd ymm3, ymm3, ymm7 vpxord ymm12, ymm12, ymm0 vpxord ymm13, ymm13, ymm1 vpxord ymm14, ymm14, ymm2 vpxord ymm15, ymm15, ymm3 vprord ymm12, ymm12, 8 vprord ymm13, ymm13, 8 vprord ymm14, ymm14, 8 vprord ymm15, ymm15, 8 vpaddd ymm8, ymm8, ymm12 vpaddd ymm9, ymm9, ymm13 vpaddd ymm10, ymm10, ymm14 vpaddd ymm11, ymm11, ymm15 vpxord ymm4, ymm4, ymm8 vpxord ymm5, ymm5, ymm9 vpxord ymm6, ymm6, ymm10 vpxord ymm7, ymm7, ymm11 vprord ymm4, ymm4, 7 vprord ymm5, ymm5, 7 vprord ymm6, ymm6, 7 vprord ymm7, ymm7, 7 vpaddd ymm0, ymm0, ymm29 vpaddd ymm1, ymm1, ymm16 vpaddd ymm2, ymm2, ymm18 vpaddd ymm3, ymm3, ymm20 vpaddd ymm0, ymm0, ymm5 vpaddd ymm1, ymm1, ymm6 vpaddd ymm2, ymm2, ymm7 vpaddd ymm3, ymm3, ymm4 vpxord ymm15, ymm15, ymm0 vpxord ymm12, ymm12, ymm1 vpxord ymm13, ymm13, ymm2 vpxord ymm14, ymm14, ymm3 vprord ymm15, ymm15, 16 vprord ymm12, ymm12, 16 vprord ymm13, ymm13, 16 vprord ymm14, ymm14, 16 vpaddd ymm10, ymm10, ymm15 vpaddd ymm11, ymm11, ymm12 vpaddd ymm8, ymm8, ymm13 vpaddd ymm9, ymm9, ymm14 vpxord ymm5, ymm5, ymm10 vpxord ymm6, ymm6, ymm11 vpxord ymm7, ymm7, ymm8 vpxord ymm4, ymm4, ymm9 vprord ymm5, ymm5, 12 vprord ymm6, ymm6, 12 vprord ymm7, ymm7, 12 vprord ymm4, ymm4, 12 vpaddd ymm0, ymm0, ymm19 vpaddd ymm1, ymm1, ymm26 vpaddd ymm2, ymm2, ymm22 vpaddd ymm3, ymm3, ymm23 vpaddd ymm0, ymm0, ymm5 vpaddd ymm1, ymm1, ymm6 vpaddd ymm2, ymm2, ymm7 vpaddd ymm3, ymm3, ymm4 vpxord ymm15, ymm15, ymm0 vpxord ymm12, ymm12, ymm1 vpxord ymm13, ymm13, ymm2 vpxord ymm14, ymm14, ymm3 vprord ymm15, ymm15, 8 vprord ymm12, ymm12, 8 vprord ymm13, ymm13, 8 vprord ymm14, ymm14, 8 vpaddd ymm10, ymm10, ymm15 vpaddd ymm11, ymm11, ymm12 vpaddd ymm8, ymm8, ymm13 vpaddd ymm9, ymm9, ymm14 vpxord ymm5, ymm5, ymm10 vpxord ymm6, ymm6, ymm11 vpxord ymm7, ymm7, ymm8 vpxord ymm4, ymm4, ymm9 vprord ymm5, ymm5, 7 vprord ymm6, ymm6, 7 vprord ymm7, ymm7, 7 vprord ymm4, ymm4, 7 vpaddd ymm0, ymm0, ymm27 vpaddd ymm1, ymm1, ymm21 vpaddd ymm2, ymm2, ymm17 vpaddd ymm3, ymm3, ymm24 vpaddd ymm0, ymm0, ymm4 vpaddd ymm1, ymm1, ymm5 vpaddd ymm2, ymm2, ymm6 vpaddd ymm3, ymm3, ymm7 vpxord ymm12, ymm12, ymm0 vpxord ymm13, ymm13, ymm1 vpxord ymm14, ymm14, ymm2 vpxord ymm15, ymm15, ymm3 vprord ymm12, ymm12, 16 vprord ymm13, ymm13, 16 vprord ymm14, ymm14, 16 vprord ymm15, ymm15, 16 vpaddd ymm8, ymm8, ymm12 vpaddd ymm9, ymm9, ymm13 vpaddd ymm10, ymm10, ymm14 vpaddd ymm11, ymm11, ymm15 vpxord ymm4, ymm4, ymm8 vpxord ymm5, ymm5, ymm9 vpxord ymm6, ymm6, ymm10 vpxord ymm7, ymm7, ymm11 vprord ymm4, ymm4, 12 vprord ymm5, ymm5, 12 vprord ymm6, ymm6, 12 vprord ymm7, ymm7, 12 vpaddd ymm0, ymm0, ymm31 vpaddd ymm1, ymm1, ymm16 vpaddd ymm2, ymm2, ymm25 vpaddd ymm3, ymm3, ymm22 vpaddd ymm0, ymm0, ymm4 vpaddd ymm1, ymm1, ymm5 vpaddd ymm2, ymm2, ymm6 vpaddd ymm3, ymm3, ymm7 vpxord ymm12, ymm12, ymm0 vpxord ymm13, ymm13, ymm1 vpxord ymm14, ymm14, ymm2 vpxord ymm15, ymm15, ymm3 vprord ymm12, ymm12, 8 vprord ymm13, ymm13, 8 vprord ymm14, ymm14, 8 vprord ymm15, ymm15, 8 vpaddd ymm8, ymm8, ymm12 vpaddd ymm9, ymm9, ymm13 vpaddd ymm10, ymm10, ymm14 vpaddd ymm11, ymm11, ymm15 vpxord ymm4, ymm4, ymm8 vpxord ymm5, ymm5, ymm9 vpxord ymm6, ymm6, ymm10 vpxord ymm7, ymm7, ymm11 vprord ymm4, ymm4, 7 vprord ymm5, ymm5, 7 vprord ymm6, ymm6, 7 vprord ymm7, ymm7, 7 vpaddd ymm0, ymm0, ymm30 vpaddd ymm1, ymm1, ymm18 vpaddd ymm2, ymm2, ymm19 vpaddd ymm3, ymm3, ymm23 vpaddd ymm0, ymm0, ymm5 vpaddd ymm1, ymm1, ymm6 vpaddd ymm2, ymm2, ymm7 vpaddd ymm3, ymm3, ymm4 vpxord ymm15, ymm15, ymm0 vpxord ymm12, ymm12, ymm1 vpxord ymm13, ymm13, ymm2 vpxord ymm14, ymm14, ymm3 vprord ymm15, ymm15, 16 vprord ymm12, ymm12, 16 vprord ymm13, ymm13, 16 vprord ymm14, ymm14, 16 vpaddd ymm10, ymm10, ymm15 vpaddd ymm11, ymm11, ymm12 vpaddd ymm8, ymm8, ymm13 vpaddd ymm9, ymm9, ymm14 vpxord ymm5, ymm5, ymm10 vpxord ymm6, ymm6, ymm11 vpxord ymm7, ymm7, ymm8 vpxord ymm4, ymm4, ymm9 vprord ymm5, ymm5, 12 vprord ymm6, ymm6, 12 vprord ymm7, ymm7, 12 vprord ymm4, ymm4, 12 vpaddd ymm0, ymm0, ymm26 vpaddd ymm1, ymm1, ymm28 vpaddd ymm2, ymm2, ymm20 vpaddd ymm3, ymm3, ymm29 vpaddd ymm0, ymm0, ymm5 vpaddd ymm1, ymm1, ymm6 vpaddd ymm2, ymm2, ymm7 vpaddd ymm3, ymm3, ymm4 vpxord ymm15, ymm15, ymm0 vpxord ymm12, ymm12, ymm1 vpxord ymm13, ymm13, ymm2 vpxord ymm14, ymm14, ymm3 vprord ymm15, ymm15, 8 vprord ymm12, ymm12, 8 vprord ymm13, ymm13, 8 vprord ymm14, ymm14, 8 vpaddd ymm10, ymm10, ymm15 vpaddd ymm11, ymm11, ymm12 vpaddd ymm8, ymm8, ymm13 vpaddd ymm9, ymm9, ymm14 vpxord ymm5, ymm5, ymm10 vpxord ymm6, ymm6, ymm11 vpxord ymm7, ymm7, ymm8 vpxord ymm4, ymm4, ymm9 vprord ymm5, ymm5, 7 vprord ymm6, ymm6, 7 vprord ymm7, ymm7, 7 vprord ymm4, ymm4, 7 vpxor ymm0, ymm0, ymm8 vpxor ymm1, ymm1, ymm9 vpxor ymm2, ymm2, ymm10 vpxor ymm3, ymm3, ymm11 vpxor ymm4, ymm4, ymm12 vpxor ymm5, ymm5, ymm13 vpxor ymm6, ymm6, ymm14 vpxor ymm7, ymm7, ymm15 movzx eax, byte ptr [rbp+0x78] jne 2b mov rbx, qword ptr [rbp+0x90] vunpcklps ymm8, ymm0, ymm1 vunpcklps ymm9, ymm2, ymm3 vunpckhps ymm10, ymm0, ymm1 vunpcklps ymm11, ymm4, ymm5 vunpcklps ymm0, ymm6, ymm7 vshufps ymm12, ymm8, ymm9, 78 vblendps ymm1, ymm8, ymm12, 0xCC vshufps ymm8, ymm11, ymm0, 78 vunpckhps ymm13, ymm2, ymm3 vblendps ymm2, ymm11, ymm8, 0xCC vblendps ymm3, ymm12, ymm9, 0xCC vperm2f128 ymm12, ymm1, ymm2, 0x20 vmovups ymmword ptr [rbx], ymm12 vunpckhps ymm14, ymm4, ymm5 vblendps ymm4, ymm8, ymm0, 0xCC vunpckhps ymm15, ymm6, ymm7 vperm2f128 ymm7, ymm3, ymm4, 0x20 vmovups ymmword ptr [rbx+0x20], ymm7 vshufps ymm5, ymm10, ymm13, 78 vblendps ymm6, ymm5, ymm13, 0xCC vshufps ymm13, ymm14, ymm15, 78 vblendps ymm10, ymm10, ymm5, 0xCC vblendps ymm14, ymm14, ymm13, 0xCC vperm2f128 ymm8, ymm10, ymm14, 0x20 vmovups ymmword ptr [rbx+0x40], ymm8 vblendps ymm15, ymm13, ymm15, 0xCC vperm2f128 ymm13, ymm6, ymm15, 0x20 vmovups ymmword ptr [rbx+0x60], ymm13 vperm2f128 ymm9, ymm1, ymm2, 0x31 vperm2f128 ymm11, ymm3, ymm4, 0x31 vmovups ymmword ptr [rbx+0x80], ymm9 vperm2f128 ymm14, ymm10, ymm14, 0x31 vperm2f128 ymm15, ymm6, ymm15, 0x31 vmovups ymmword ptr [rbx+0xA0], ymm11 vmovups ymmword ptr [rbx+0xC0], ymm14 vmovups ymmword ptr [rbx+0xE0], ymm15 vmovdqa ymm0, ymmword ptr [rsp] vmovdqa ymm2, ymmword ptr [rsp+0x40] vmovdqa32 ymm0 {k1}, ymmword ptr [rsp+0x1*0x20] vmovdqa32 ymm2 {k1}, ymmword ptr [rsp+0x3*0x20] vmovdqa ymmword ptr [rsp], ymm0 vmovdqa ymmword ptr [rsp+0x40], ymm2 add rbx, 256 mov qword ptr [rbp+0x90], rbx add rdi, 64 sub rsi, 8 3: mov rbx, qword ptr [rbp+0x90] mov r15, qword ptr [rsp+0x80] movzx r13, byte ptr [rbp+0x78] movzx r12, byte ptr [rbp+0x88] test esi, 0x4 je 3f vbroadcasti32x4 zmm0, xmmword ptr [rcx] vbroadcasti32x4 zmm1, xmmword ptr [rcx+0x1*0x10] vmovdqa xmm12, xmmword ptr [rsp] vmovdqa xmm13, xmmword ptr [rsp+0x40] vpunpckldq xmm14, xmm12, xmm13 vpunpckhdq xmm15, xmm12, xmm13 vpermq ymm14, ymm14, 0xDC vpermq ymm15, ymm15, 0xDC vpbroadcastd zmm12, dword ptr [BLAKE3_BLOCK_LEN+rip] vinserti64x4 zmm13, zmm14, ymm15, 0x01 mov eax, 17476 kmovw k2, eax vpblendmd zmm13 {k2}, zmm13, zmm12 vbroadcasti32x4 zmm15, xmmword ptr [BLAKE3_IV+rip] mov r8, qword ptr [rdi] mov r9, qword ptr [rdi+0x8] mov r10, qword ptr [rdi+0x10] mov r11, qword ptr [rdi+0x18] mov eax, 43690 kmovw k3, eax mov eax, 34952 kmovw k4, eax movzx eax, byte ptr [rbp+0x80] or eax, r13d xor edx, edx .p2align 5 2: mov r14d, eax or eax, r12d add rdx, 64 cmp rdx, r15 cmovne eax, r14d mov dword ptr [rsp+0x88], eax vmovdqa32 zmm2, zmm15 vpbroadcastd zmm8, dword ptr [rsp+0x22*0x4] vpblendmd zmm3 {k4}, zmm13, zmm8 vmovups zmm8, zmmword ptr [r8+rdx-0x1*0x40] vinserti32x4 zmm8, zmm8, xmmword ptr [r9+rdx-0x4*0x10], 0x01 vinserti32x4 zmm8, zmm8, xmmword ptr [r10+rdx-0x4*0x10], 0x02 vinserti32x4 zmm8, zmm8, xmmword ptr [r11+rdx-0x4*0x10], 0x03 vmovups zmm9, zmmword ptr [r8+rdx-0x30] vinserti32x4 zmm9, zmm9, xmmword ptr [r9+rdx-0x3*0x10], 0x01 vinserti32x4 zmm9, zmm9, xmmword ptr [r10+rdx-0x3*0x10], 0x02 vinserti32x4 zmm9, zmm9, xmmword ptr [r11+rdx-0x3*0x10], 0x03 vshufps zmm4, zmm8, zmm9, 136 vshufps zmm5, zmm8, zmm9, 221 vmovups zmm8, zmmword ptr [r8+rdx-0x20] vinserti32x4 zmm8, zmm8, xmmword ptr [r9+rdx-0x2*0x10], 0x01 vinserti32x4 zmm8, zmm8, xmmword ptr [r10+rdx-0x2*0x10], 0x02 vinserti32x4 zmm8, zmm8, xmmword ptr [r11+rdx-0x2*0x10], 0x03 vmovups zmm9, zmmword ptr [r8+rdx-0x10] vinserti32x4 zmm9, zmm9, xmmword ptr [r9+rdx-0x1*0x10], 0x01 vinserti32x4 zmm9, zmm9, xmmword ptr [r10+rdx-0x1*0x10], 0x02 vinserti32x4 zmm9, zmm9, xmmword ptr [r11+rdx-0x1*0x10], 0x03 vshufps zmm6, zmm8, zmm9, 136 vshufps zmm7, zmm8, zmm9, 221 vpshufd zmm6, zmm6, 0x93 vpshufd zmm7, zmm7, 0x93 mov al, 7 9: vpaddd zmm0, zmm0, zmm4 vpaddd zmm0, zmm0, zmm1 vpxord zmm3, zmm3, zmm0 vprord zmm3, zmm3, 16 vpaddd zmm2, zmm2, zmm3 vpxord zmm1, zmm1, zmm2 vprord zmm1, zmm1, 12 vpaddd zmm0, zmm0, zmm5 vpaddd zmm0, zmm0, zmm1 vpxord zmm3, zmm3, zmm0 vprord zmm3, zmm3, 8 vpaddd zmm2, zmm2, zmm3 vpxord zmm1, zmm1, zmm2 vprord zmm1, zmm1, 7 vpshufd zmm0, zmm0, 0x93 vpshufd zmm3, zmm3, 0x4E vpshufd zmm2, zmm2, 0x39 vpaddd zmm0, zmm0, zmm6 vpaddd zmm0, zmm0, zmm1 vpxord zmm3, zmm3, zmm0 vprord zmm3, zmm3, 16 vpaddd zmm2, zmm2, zmm3 vpxord zmm1, zmm1, zmm2 vprord zmm1, zmm1, 12 vpaddd zmm0, zmm0, zmm7 vpaddd zmm0, zmm0, zmm1 vpxord zmm3, zmm3, zmm0 vprord zmm3, zmm3, 8 vpaddd zmm2, zmm2, zmm3 vpxord zmm1, zmm1, zmm2 vprord zmm1, zmm1, 7 vpshufd zmm0, zmm0, 0x39 vpshufd zmm3, zmm3, 0x4E vpshufd zmm2, zmm2, 0x93 dec al jz 9f vshufps zmm8, zmm4, zmm5, 214 vpshufd zmm9, zmm4, 0x0F vpshufd zmm4, zmm8, 0x39 vshufps zmm8, zmm6, zmm7, 250 vpblendmd zmm9 {k3}, zmm9, zmm8 vpunpcklqdq zmm8, zmm7, zmm5 vpblendmd zmm8 {k4}, zmm8, zmm6 vpshufd zmm8, zmm8, 0x78 vpunpckhdq zmm5, zmm5, zmm7 vpunpckldq zmm6, zmm6, zmm5 vpshufd zmm7, zmm6, 0x1E vmovdqa32 zmm5, zmm9 vmovdqa32 zmm6, zmm8 jmp 9b 9: vpxord zmm0, zmm0, zmm2 vpxord zmm1, zmm1, zmm3 mov eax, r13d cmp rdx, r15 jne 2b vmovdqu xmmword ptr [rbx], xmm0 vmovdqu xmmword ptr [rbx+0x10], xmm1 vextracti128 xmmword ptr [rbx+0x20], ymm0, 0x01 vextracti128 xmmword ptr [rbx+0x30], ymm1, 0x01 vextracti32x4 xmmword ptr [rbx+0x4*0x10], zmm0, 0x02 vextracti32x4 xmmword ptr [rbx+0x5*0x10], zmm1, 0x02 vextracti32x4 xmmword ptr [rbx+0x6*0x10], zmm0, 0x03 vextracti32x4 xmmword ptr [rbx+0x7*0x10], zmm1, 0x03 vmovdqa xmm0, xmmword ptr [rsp] vmovdqa xmm2, xmmword ptr [rsp+0x40] vmovdqa32 xmm0 {k1}, xmmword ptr [rsp+0x1*0x10] vmovdqa32 xmm2 {k1}, xmmword ptr [rsp+0x5*0x10] vmovdqa xmmword ptr [rsp], xmm0 vmovdqa xmmword ptr [rsp+0x40], xmm2 add rbx, 128 add rdi, 32 sub rsi, 4 3: test esi, 0x2 je 3f vbroadcasti128 ymm0, xmmword ptr [rcx] vbroadcasti128 ymm1, xmmword ptr [rcx+0x10] vmovd xmm13, dword ptr [rsp] vpinsrd xmm13, xmm13, dword ptr [rsp+0x40], 1 vpinsrd xmm13, xmm13, dword ptr [BLAKE3_BLOCK_LEN+rip], 2 vmovd xmm14, dword ptr [rsp+0x4] vpinsrd xmm14, xmm14, dword ptr [rsp+0x44], 1 vpinsrd xmm14, xmm14, dword ptr [BLAKE3_BLOCK_LEN+rip], 2 vinserti128 ymm13, ymm13, xmm14, 0x01 mov r8, qword ptr [rdi] mov r9, qword ptr [rdi+0x8] movzx eax, byte ptr [rbp+0x80] or eax, r13d xor edx, edx .p2align 5 2: mov r14d, eax or eax, r12d add rdx, 64 cmp rdx, r15 cmovne eax, r14d mov dword ptr [rsp+0x88], eax vbroadcasti128 ymm2, xmmword ptr [BLAKE3_IV+rip] vpbroadcastd ymm8, dword ptr [rsp+0x88] vpblendd ymm3, ymm13, ymm8, 0x88 vmovups ymm8, ymmword ptr [r8+rdx-0x40] vinsertf128 ymm8, ymm8, xmmword ptr [r9+rdx-0x40], 0x01 vmovups ymm9, ymmword ptr [r8+rdx-0x30] vinsertf128 ymm9, ymm9, xmmword ptr [r9+rdx-0x30], 0x01 vshufps ymm4, ymm8, ymm9, 136 vshufps ymm5, ymm8, ymm9, 221 vmovups ymm8, ymmword ptr [r8+rdx-0x20] vinsertf128 ymm8, ymm8, xmmword ptr [r9+rdx-0x20], 0x01 vmovups ymm9, ymmword ptr [r8+rdx-0x10] vinsertf128 ymm9, ymm9, xmmword ptr [r9+rdx-0x10], 0x01 vshufps ymm6, ymm8, ymm9, 136 vshufps ymm7, ymm8, ymm9, 221 vpshufd ymm6, ymm6, 0x93 vpshufd ymm7, ymm7, 0x93 mov al, 7 9: vpaddd ymm0, ymm0, ymm4 vpaddd ymm0, ymm0, ymm1 vpxord ymm3, ymm3, ymm0 vprord ymm3, ymm3, 16 vpaddd ymm2, ymm2, ymm3 vpxord ymm1, ymm1, ymm2 vprord ymm1, ymm1, 12 vpaddd ymm0, ymm0, ymm5 vpaddd ymm0, ymm0, ymm1 vpxord ymm3, ymm3, ymm0 vprord ymm3, ymm3, 8 vpaddd ymm2, ymm2, ymm3 vpxord ymm1, ymm1, ymm2 vprord ymm1, ymm1, 7 vpshufd ymm0, ymm0, 0x93 vpshufd ymm3, ymm3, 0x4E vpshufd ymm2, ymm2, 0x39 vpaddd ymm0, ymm0, ymm6 vpaddd ymm0, ymm0, ymm1 vpxord ymm3, ymm3, ymm0 vprord ymm3, ymm3, 16 vpaddd ymm2, ymm2, ymm3 vpxord ymm1, ymm1, ymm2 vprord ymm1, ymm1, 12 vpaddd ymm0, ymm0, ymm7 vpaddd ymm0, ymm0, ymm1 vpxord ymm3, ymm3, ymm0 vprord ymm3, ymm3, 8 vpaddd ymm2, ymm2, ymm3 vpxord ymm1, ymm1, ymm2 vprord ymm1, ymm1, 7 vpshufd ymm0, ymm0, 0x39 vpshufd ymm3, ymm3, 0x4E vpshufd ymm2, ymm2, 0x93 dec al jz 9f vshufps ymm8, ymm4, ymm5, 214 vpshufd ymm9, ymm4, 0x0F vpshufd ymm4, ymm8, 0x39 vshufps ymm8, ymm6, ymm7, 250 vpblendd ymm9, ymm9, ymm8, 0xAA vpunpcklqdq ymm8, ymm7, ymm5 vpblendd ymm8, ymm8, ymm6, 0x88 vpshufd ymm8, ymm8, 0x78 vpunpckhdq ymm5, ymm5, ymm7 vpunpckldq ymm6, ymm6, ymm5 vpshufd ymm7, ymm6, 0x1E vmovdqa ymm5, ymm9 vmovdqa ymm6, ymm8 jmp 9b 9: vpxor ymm0, ymm0, ymm2 vpxor ymm1, ymm1, ymm3 mov eax, r13d cmp rdx, r15 jne 2b vmovdqu xmmword ptr [rbx], xmm0 vmovdqu xmmword ptr [rbx+0x10], xmm1 vextracti128 xmmword ptr [rbx+0x20], ymm0, 0x01 vextracti128 xmmword ptr [rbx+0x30], ymm1, 0x01 vmovdqa xmm0, xmmword ptr [rsp] vmovdqa xmm2, xmmword ptr [rsp+0x40] vmovdqu32 xmm0 {k1}, xmmword ptr [rsp+0x8] vmovdqu32 xmm2 {k1}, xmmword ptr [rsp+0x48] vmovdqa xmmword ptr [rsp], xmm0 vmovdqa xmmword ptr [rsp+0x40], xmm2 add rbx, 64 add rdi, 16 sub rsi, 2 3: test esi, 0x1 je 4b vmovdqu xmm0, xmmword ptr [rcx] vmovdqu xmm1, xmmword ptr [rcx+0x10] vmovd xmm14, dword ptr [rsp] vpinsrd xmm14, xmm14, dword ptr [rsp+0x40], 1 vpinsrd xmm14, xmm14, dword ptr [BLAKE3_BLOCK_LEN+rip], 2 vmovdqa xmm15, xmmword ptr [BLAKE3_IV+rip] mov r8, qword ptr [rdi] movzx eax, byte ptr [rbp+0x80] or eax, r13d xor edx, edx .p2align 5 2: mov r14d, eax or eax, r12d add rdx, 64 cmp rdx, r15 cmovne eax, r14d vpinsrd xmm3, xmm14, eax, 3 vmovdqa xmm2, xmm15 vmovups xmm8, xmmword ptr [r8+rdx-0x40] vmovups xmm9, xmmword ptr [r8+rdx-0x30] vshufps xmm4, xmm8, xmm9, 136 vshufps xmm5, xmm8, xmm9, 221 vmovups xmm8, xmmword ptr [r8+rdx-0x20] vmovups xmm9, xmmword ptr [r8+rdx-0x10] vshufps xmm6, xmm8, xmm9, 136 vshufps xmm7, xmm8, xmm9, 221 vpshufd xmm6, xmm6, 0x93 vpshufd xmm7, xmm7, 0x93 mov al, 7 9: vpaddd xmm0, xmm0, xmm4 vpaddd xmm0, xmm0, xmm1 vpxord xmm3, xmm3, xmm0 vprord xmm3, xmm3, 16 vpaddd xmm2, xmm2, xmm3 vpxord xmm1, xmm1, xmm2 vprord xmm1, xmm1, 12 vpaddd xmm0, xmm0, xmm5 vpaddd xmm0, xmm0, xmm1 vpxord xmm3, xmm3, xmm0 vprord xmm3, xmm3, 8 vpaddd xmm2, xmm2, xmm3 vpxord xmm1, xmm1, xmm2 vprord xmm1, xmm1, 7 vpshufd xmm0, xmm0, 0x93 vpshufd xmm3, xmm3, 0x4E vpshufd xmm2, xmm2, 0x39 vpaddd xmm0, xmm0, xmm6 vpaddd xmm0, xmm0, xmm1 vpxord xmm3, xmm3, xmm0 vprord xmm3, xmm3, 16 vpaddd xmm2, xmm2, xmm3 vpxord xmm1, xmm1, xmm2 vprord xmm1, xmm1, 12 vpaddd xmm0, xmm0, xmm7 vpaddd xmm0, xmm0, xmm1 vpxord xmm3, xmm3, xmm0 vprord xmm3, xmm3, 8 vpaddd xmm2, xmm2, xmm3 vpxord xmm1, xmm1, xmm2 vprord xmm1, xmm1, 7 vpshufd xmm0, xmm0, 0x39 vpshufd xmm3, xmm3, 0x4E vpshufd xmm2, xmm2, 0x93 dec al jz 9f vshufps xmm8, xmm4, xmm5, 214 vpshufd xmm9, xmm4, 0x0F vpshufd xmm4, xmm8, 0x39 vshufps xmm8, xmm6, xmm7, 250 vpblendd xmm9, xmm9, xmm8, 0xAA vpunpcklqdq xmm8, xmm7, xmm5 vpblendd xmm8, xmm8, xmm6, 0x88 vpshufd xmm8, xmm8, 0x78 vpunpckhdq xmm5, xmm5, xmm7 vpunpckldq xmm6, xmm6, xmm5 vpshufd xmm7, xmm6, 0x1E vmovdqa xmm5, xmm9 vmovdqa xmm6, xmm8 jmp 9b 9: vpxor xmm0, xmm0, xmm2 vpxor xmm1, xmm1, xmm3 mov eax, r13d cmp rdx, r15 jne 2b vmovdqu xmmword ptr [rbx], xmm0 vmovdqu xmmword ptr [rbx+0x10], xmm1 jmp 4b .p2align 6 _blake3_compress_in_place_avx512: blake3_compress_in_place_avx512: sub rsp, 72 vmovdqa xmmword ptr [rsp], xmm6 vmovdqa xmmword ptr [rsp+0x10], xmm7 vmovdqa xmmword ptr [rsp+0x20], xmm8 vmovdqa xmmword ptr [rsp+0x30], xmm9 vmovdqu xmm0, xmmword ptr [rcx] vmovdqu xmm1, xmmword ptr [rcx+0x10] movzx eax, byte ptr [rsp+0x70] movzx r8d, r8b shl rax, 32 add r8, rax vmovq xmm3, r9 vmovq xmm4, r8 vpunpcklqdq xmm3, xmm3, xmm4 vmovaps xmm2, xmmword ptr [BLAKE3_IV+rip] vmovups xmm8, xmmword ptr [rdx] vmovups xmm9, xmmword ptr [rdx+0x10] vshufps xmm4, xmm8, xmm9, 136 vshufps xmm5, xmm8, xmm9, 221 vmovups xmm8, xmmword ptr [rdx+0x20] vmovups xmm9, xmmword ptr [rdx+0x30] vshufps xmm6, xmm8, xmm9, 136 vshufps xmm7, xmm8, xmm9, 221 vpshufd xmm6, xmm6, 0x93 vpshufd xmm7, xmm7, 0x93 mov al, 7 9: vpaddd xmm0, xmm0, xmm4 vpaddd xmm0, xmm0, xmm1 vpxord xmm3, xmm3, xmm0 vprord xmm3, xmm3, 16 vpaddd xmm2, xmm2, xmm3 vpxord xmm1, xmm1, xmm2 vprord xmm1, xmm1, 12 vpaddd xmm0, xmm0, xmm5 vpaddd xmm0, xmm0, xmm1 vpxord xmm3, xmm3, xmm0 vprord xmm3, xmm3, 8 vpaddd xmm2, xmm2, xmm3 vpxord xmm1, xmm1, xmm2 vprord xmm1, xmm1, 7 vpshufd xmm0, xmm0, 0x93 vpshufd xmm3, xmm3, 0x4E vpshufd xmm2, xmm2, 0x39 vpaddd xmm0, xmm0, xmm6 vpaddd xmm0, xmm0, xmm1 vpxord xmm3, xmm3, xmm0 vprord xmm3, xmm3, 16 vpaddd xmm2, xmm2, xmm3 vpxord xmm1, xmm1, xmm2 vprord xmm1, xmm1, 12 vpaddd xmm0, xmm0, xmm7 vpaddd xmm0, xmm0, xmm1 vpxord xmm3, xmm3, xmm0 vprord xmm3, xmm3, 8 vpaddd xmm2, xmm2, xmm3 vpxord xmm1, xmm1, xmm2 vprord xmm1, xmm1, 7 vpshufd xmm0, xmm0, 0x39 vpshufd xmm3, xmm3, 0x4E vpshufd xmm2, xmm2, 0x93 dec al jz 9f vshufps xmm8, xmm4, xmm5, 214 vpshufd xmm9, xmm4, 0x0F vpshufd xmm4, xmm8, 0x39 vshufps xmm8, xmm6, xmm7, 250 vpblendd xmm9, xmm9, xmm8, 0xAA vpunpcklqdq xmm8, xmm7, xmm5 vpblendd xmm8, xmm8, xmm6, 0x88 vpshufd xmm8, xmm8, 0x78 vpunpckhdq xmm5, xmm5, xmm7 vpunpckldq xmm6, xmm6, xmm5 vpshufd xmm7, xmm6, 0x1E vmovdqa xmm5, xmm9 vmovdqa xmm6, xmm8 jmp 9b 9: vpxor xmm0, xmm0, xmm2 vpxor xmm1, xmm1, xmm3 vmovdqu xmmword ptr [rcx], xmm0 vmovdqu xmmword ptr [rcx+0x10], xmm1 vmovdqa xmm6, xmmword ptr [rsp] vmovdqa xmm7, xmmword ptr [rsp+0x10] vmovdqa xmm8, xmmword ptr [rsp+0x20] vmovdqa xmm9, xmmword ptr [rsp+0x30] add rsp, 72 ret .p2align 6 _blake3_compress_xof_avx512: blake3_compress_xof_avx512: sub rsp, 72 vmovdqa xmmword ptr [rsp], xmm6 vmovdqa xmmword ptr [rsp+0x10], xmm7 vmovdqa xmmword ptr [rsp+0x20], xmm8 vmovdqa xmmword ptr [rsp+0x30], xmm9 vmovdqu xmm0, xmmword ptr [rcx] vmovdqu xmm1, xmmword ptr [rcx+0x10] movzx eax, byte ptr [rsp+0x70] movzx r8d, r8b mov r10, qword ptr [rsp+0x78] shl rax, 32 add r8, rax vmovq xmm3, r9 vmovq xmm4, r8 vpunpcklqdq xmm3, xmm3, xmm4 vmovaps xmm2, xmmword ptr [BLAKE3_IV+rip] vmovups xmm8, xmmword ptr [rdx] vmovups xmm9, xmmword ptr [rdx+0x10] vshufps xmm4, xmm8, xmm9, 136 vshufps xmm5, xmm8, xmm9, 221 vmovups xmm8, xmmword ptr [rdx+0x20] vmovups xmm9, xmmword ptr [rdx+0x30] vshufps xmm6, xmm8, xmm9, 136 vshufps xmm7, xmm8, xmm9, 221 vpshufd xmm6, xmm6, 0x93 vpshufd xmm7, xmm7, 0x93 mov al, 7 9: vpaddd xmm0, xmm0, xmm4 vpaddd xmm0, xmm0, xmm1 vpxord xmm3, xmm3, xmm0 vprord xmm3, xmm3, 16 vpaddd xmm2, xmm2, xmm3 vpxord xmm1, xmm1, xmm2 vprord xmm1, xmm1, 12 vpaddd xmm0, xmm0, xmm5 vpaddd xmm0, xmm0, xmm1 vpxord xmm3, xmm3, xmm0 vprord xmm3, xmm3, 8 vpaddd xmm2, xmm2, xmm3 vpxord xmm1, xmm1, xmm2 vprord xmm1, xmm1, 7 vpshufd xmm0, xmm0, 0x93 vpshufd xmm3, xmm3, 0x4E vpshufd xmm2, xmm2, 0x39 vpaddd xmm0, xmm0, xmm6 vpaddd xmm0, xmm0, xmm1 vpxord xmm3, xmm3, xmm0 vprord xmm3, xmm3, 16 vpaddd xmm2, xmm2, xmm3 vpxord xmm1, xmm1, xmm2 vprord xmm1, xmm1, 12 vpaddd xmm0, xmm0, xmm7 vpaddd xmm0, xmm0, xmm1 vpxord xmm3, xmm3, xmm0 vprord xmm3, xmm3, 8 vpaddd xmm2, xmm2, xmm3 vpxord xmm1, xmm1, xmm2 vprord xmm1, xmm1, 7 vpshufd xmm0, xmm0, 0x39 vpshufd xmm3, xmm3, 0x4E vpshufd xmm2, xmm2, 0x93 dec al jz 9f vshufps xmm8, xmm4, xmm5, 214 vpshufd xmm9, xmm4, 0x0F vpshufd xmm4, xmm8, 0x39 vshufps xmm8, xmm6, xmm7, 250 vpblendd xmm9, xmm9, xmm8, 0xAA vpunpcklqdq xmm8, xmm7, xmm5 vpblendd xmm8, xmm8, xmm6, 0x88 vpshufd xmm8, xmm8, 0x78 vpunpckhdq xmm5, xmm5, xmm7 vpunpckldq xmm6, xmm6, xmm5 vpshufd xmm7, xmm6, 0x1E vmovdqa xmm5, xmm9 vmovdqa xmm6, xmm8 jmp 9b 9: vpxor xmm0, xmm0, xmm2 vpxor xmm1, xmm1, xmm3 vpxor xmm2, xmm2, xmmword ptr [rcx] vpxor xmm3, xmm3, xmmword ptr [rcx+0x10] vmovdqu xmmword ptr [r10], xmm0 vmovdqu xmmword ptr [r10+0x10], xmm1 vmovdqu xmmword ptr [r10+0x20], xmm2 vmovdqu xmmword ptr [r10+0x30], xmm3 vmovdqa xmm6, xmmword ptr [rsp] vmovdqa xmm7, xmmword ptr [rsp+0x10] vmovdqa xmm8, xmmword ptr [rsp+0x20] vmovdqa xmm9, xmmword ptr [rsp+0x30] add rsp, 72 ret .section .rdata .p2align 6 INDEX0: .long 0, 1, 2, 3, 16, 17, 18, 19 .long 8, 9, 10, 11, 24, 25, 26, 27 INDEX1: .long 4, 5, 6, 7, 20, 21, 22, 23 .long 12, 13, 14, 15, 28, 29, 30, 31 ADD0: .long 0, 1, 2, 3, 4, 5, 6, 7 .long 8, 9, 10, 11, 12, 13, 14, 15 ADD1: .long 1 ADD16: .long 16 BLAKE3_BLOCK_LEN: .long 64 .p2align 6 BLAKE3_IV: BLAKE3_IV_0: .long 0x6A09E667 BLAKE3_IV_1: .long 0xBB67AE85 BLAKE3_IV_2: .long 0x3C6EF372 BLAKE3_IV_3: .long 0xA54FF53A librecast/libs/blake3/c/blake3_avx512_x86-64_windows_msvc.asm000066400000000000000000002627251502456746400241040ustar00rootroot00000000000000public _blake3_hash_many_avx512 public blake3_hash_many_avx512 public blake3_compress_in_place_avx512 public _blake3_compress_in_place_avx512 public blake3_compress_xof_avx512 public _blake3_compress_xof_avx512 _TEXT SEGMENT ALIGN(16) 'CODE' ALIGN 16 blake3_hash_many_avx512 PROC _blake3_hash_many_avx512 PROC push r15 push r14 push r13 push r12 push rdi push rsi push rbx push rbp mov rbp, rsp sub rsp, 304 and rsp, 0FFFFFFFFFFFFFFC0H vmovdqa xmmword ptr [rsp+90H], xmm6 vmovdqa xmmword ptr [rsp+0A0H], xmm7 vmovdqa xmmword ptr [rsp+0B0H], xmm8 vmovdqa xmmword ptr [rsp+0C0H], xmm9 vmovdqa xmmword ptr [rsp+0D0H], xmm10 vmovdqa xmmword ptr [rsp+0E0H], xmm11 vmovdqa xmmword ptr [rsp+0F0H], xmm12 vmovdqa xmmword ptr [rsp+100H], xmm13 vmovdqa xmmword ptr [rsp+110H], xmm14 vmovdqa xmmword ptr [rsp+120H], xmm15 mov rdi, rcx mov rsi, rdx mov rdx, r8 mov rcx, r9 mov r8, qword ptr [rbp+68H] movzx r9, byte ptr [rbp+70H] neg r9 kmovw k1, r9d vmovd xmm0, r8d vpbroadcastd ymm0, xmm0 shr r8, 32 vmovd xmm1, r8d vpbroadcastd ymm1, xmm1 vmovdqa ymm4, ymm1 vmovdqa ymm5, ymm1 vpaddd ymm2, ymm0, ymmword ptr [ADD0] vpaddd ymm3, ymm0, ymmword ptr [ADD0+32] vpcmpud k2, ymm2, ymm0, 1 vpcmpud k3, ymm3, ymm0, 1 ; XXX: ml64.exe does not currently understand the syntax. We use a workaround. vpbroadcastd ymm6, dword ptr [ADD1] vpaddd ymm4 {k2}, ymm4, ymm6 vpaddd ymm5 {k3}, ymm5, ymm6 ; vpaddd ymm4 {k2}, ymm4, dword ptr [ADD1] {1to8} ; vpaddd ymm5 {k3}, ymm5, dword ptr [ADD1] {1to8} knotw k2, k1 vmovdqa32 ymm2 {k2}, ymm0 vmovdqa32 ymm3 {k2}, ymm0 vmovdqa32 ymm4 {k2}, ymm1 vmovdqa32 ymm5 {k2}, ymm1 vmovdqa ymmword ptr [rsp], ymm2 vmovdqa ymmword ptr [rsp+20H], ymm3 vmovdqa ymmword ptr [rsp+40H], ymm4 vmovdqa ymmword ptr [rsp+60H], ymm5 shl rdx, 6 mov qword ptr [rsp+80H], rdx cmp rsi, 16 jc final15blocks outerloop16: vpbroadcastd zmm0, dword ptr [rcx] vpbroadcastd zmm1, dword ptr [rcx+1H*4H] vpbroadcastd zmm2, dword ptr [rcx+2H*4H] vpbroadcastd zmm3, dword ptr [rcx+3H*4H] vpbroadcastd zmm4, dword ptr [rcx+4H*4H] vpbroadcastd zmm5, dword ptr [rcx+5H*4H] vpbroadcastd zmm6, dword ptr [rcx+6H*4H] vpbroadcastd zmm7, dword ptr [rcx+7H*4H] movzx eax, byte ptr [rbp+78H] movzx ebx, byte ptr [rbp+80H] or eax, ebx xor edx, edx ALIGN 16 innerloop16: movzx ebx, byte ptr [rbp+88H] or ebx, eax add rdx, 64 cmp rdx, qword ptr [rsp+80H] cmove eax, ebx mov dword ptr [rsp+88H], eax mov r8, qword ptr [rdi] mov r9, qword ptr [rdi+8H] mov r10, qword ptr [rdi+10H] mov r11, qword ptr [rdi+18H] mov r12, qword ptr [rdi+40H] mov r13, qword ptr [rdi+48H] mov r14, qword ptr [rdi+50H] mov r15, qword ptr [rdi+58H] vmovdqu32 ymm16, ymmword ptr [rdx+r8-2H*20H] vinserti64x4 zmm16, zmm16, ymmword ptr [rdx+r12-2H*20H], 01H vmovdqu32 ymm17, ymmword ptr [rdx+r9-2H*20H] vinserti64x4 zmm17, zmm17, ymmword ptr [rdx+r13-2H*20H], 01H vpunpcklqdq zmm8, zmm16, zmm17 vpunpckhqdq zmm9, zmm16, zmm17 vmovdqu32 ymm18, ymmword ptr [rdx+r10-2H*20H] vinserti64x4 zmm18, zmm18, ymmword ptr [rdx+r14-2H*20H], 01H vmovdqu32 ymm19, ymmword ptr [rdx+r11-2H*20H] vinserti64x4 zmm19, zmm19, ymmword ptr [rdx+r15-2H*20H], 01H vpunpcklqdq zmm10, zmm18, zmm19 vpunpckhqdq zmm11, zmm18, zmm19 mov r8, qword ptr [rdi+20H] mov r9, qword ptr [rdi+28H] mov r10, qword ptr [rdi+30H] mov r11, qword ptr [rdi+38H] mov r12, qword ptr [rdi+60H] mov r13, qword ptr [rdi+68H] mov r14, qword ptr [rdi+70H] mov r15, qword ptr [rdi+78H] vmovdqu32 ymm16, ymmword ptr [rdx+r8-2H*20H] vinserti64x4 zmm16, zmm16, ymmword ptr [rdx+r12-2H*20H], 01H vmovdqu32 ymm17, ymmword ptr [rdx+r9-2H*20H] vinserti64x4 zmm17, zmm17, ymmword ptr [rdx+r13-2H*20H], 01H vpunpcklqdq zmm12, zmm16, zmm17 vpunpckhqdq zmm13, zmm16, zmm17 vmovdqu32 ymm18, ymmword ptr [rdx+r10-2H*20H] vinserti64x4 zmm18, zmm18, ymmword ptr [rdx+r14-2H*20H], 01H vmovdqu32 ymm19, ymmword ptr [rdx+r11-2H*20H] vinserti64x4 zmm19, zmm19, ymmword ptr [rdx+r15-2H*20H], 01H vpunpcklqdq zmm14, zmm18, zmm19 vpunpckhqdq zmm15, zmm18, zmm19 vmovdqa32 zmm27, zmmword ptr [INDEX0] vmovdqa32 zmm31, zmmword ptr [INDEX1] vshufps zmm16, zmm8, zmm10, 136 vshufps zmm17, zmm12, zmm14, 136 vmovdqa32 zmm20, zmm16 vpermt2d zmm16, zmm27, zmm17 vpermt2d zmm20, zmm31, zmm17 vshufps zmm17, zmm8, zmm10, 221 vshufps zmm30, zmm12, zmm14, 221 vmovdqa32 zmm21, zmm17 vpermt2d zmm17, zmm27, zmm30 vpermt2d zmm21, zmm31, zmm30 vshufps zmm18, zmm9, zmm11, 136 vshufps zmm8, zmm13, zmm15, 136 vmovdqa32 zmm22, zmm18 vpermt2d zmm18, zmm27, zmm8 vpermt2d zmm22, zmm31, zmm8 vshufps zmm19, zmm9, zmm11, 221 vshufps zmm8, zmm13, zmm15, 221 vmovdqa32 zmm23, zmm19 vpermt2d zmm19, zmm27, zmm8 vpermt2d zmm23, zmm31, zmm8 mov r8, qword ptr [rdi] mov r9, qword ptr [rdi+8H] mov r10, qword ptr [rdi+10H] mov r11, qword ptr [rdi+18H] mov r12, qword ptr [rdi+40H] mov r13, qword ptr [rdi+48H] mov r14, qword ptr [rdi+50H] mov r15, qword ptr [rdi+58H] vmovdqu32 ymm24, ymmword ptr [r8+rdx-1H*20H] vinserti64x4 zmm24, zmm24, ymmword ptr [r12+rdx-1H*20H], 01H vmovdqu32 ymm25, ymmword ptr [r9+rdx-1H*20H] vinserti64x4 zmm25, zmm25, ymmword ptr [r13+rdx-1H*20H], 01H vpunpcklqdq zmm8, zmm24, zmm25 vpunpckhqdq zmm9, zmm24, zmm25 vmovdqu32 ymm24, ymmword ptr [r10+rdx-1H*20H] vinserti64x4 zmm24, zmm24, ymmword ptr [r14+rdx-1H*20H], 01H vmovdqu32 ymm25, ymmword ptr [r11+rdx-1H*20H] vinserti64x4 zmm25, zmm25, ymmword ptr [r15+rdx-1H*20H], 01H vpunpcklqdq zmm10, zmm24, zmm25 vpunpckhqdq zmm11, zmm24, zmm25 prefetcht0 byte ptr [r8+rdx+80H] prefetcht0 byte ptr [r12+rdx+80H] prefetcht0 byte ptr [r9+rdx+80H] prefetcht0 byte ptr [r13+rdx+80H] prefetcht0 byte ptr [r10+rdx+80H] prefetcht0 byte ptr [r14+rdx+80H] prefetcht0 byte ptr [r11+rdx+80H] prefetcht0 byte ptr [r15+rdx+80H] mov r8, qword ptr [rdi+20H] mov r9, qword ptr [rdi+28H] mov r10, qword ptr [rdi+30H] mov r11, qword ptr [rdi+38H] mov r12, qword ptr [rdi+60H] mov r13, qword ptr [rdi+68H] mov r14, qword ptr [rdi+70H] mov r15, qword ptr [rdi+78H] vmovdqu32 ymm24, ymmword ptr [r8+rdx-1H*20H] vinserti64x4 zmm24, zmm24, ymmword ptr [r12+rdx-1H*20H], 01H vmovdqu32 ymm25, ymmword ptr [r9+rdx-1H*20H] vinserti64x4 zmm25, zmm25, ymmword ptr [r13+rdx-1H*20H], 01H vpunpcklqdq zmm12, zmm24, zmm25 vpunpckhqdq zmm13, zmm24, zmm25 vmovdqu32 ymm24, ymmword ptr [r10+rdx-1H*20H] vinserti64x4 zmm24, zmm24, ymmword ptr [r14+rdx-1H*20H], 01H vmovdqu32 ymm25, ymmword ptr [r11+rdx-1H*20H] vinserti64x4 zmm25, zmm25, ymmword ptr [r15+rdx-1H*20H], 01H vpunpcklqdq zmm14, zmm24, zmm25 vpunpckhqdq zmm15, zmm24, zmm25 prefetcht0 byte ptr [r8+rdx+80H] prefetcht0 byte ptr [r12+rdx+80H] prefetcht0 byte ptr [r9+rdx+80H] prefetcht0 byte ptr [r13+rdx+80H] prefetcht0 byte ptr [r10+rdx+80H] prefetcht0 byte ptr [r14+rdx+80H] prefetcht0 byte ptr [r11+rdx+80H] prefetcht0 byte ptr [r15+rdx+80H] vshufps zmm24, zmm8, zmm10, 136 vshufps zmm30, zmm12, zmm14, 136 vmovdqa32 zmm28, zmm24 vpermt2d zmm24, zmm27, zmm30 vpermt2d zmm28, zmm31, zmm30 vshufps zmm25, zmm8, zmm10, 221 vshufps zmm30, zmm12, zmm14, 221 vmovdqa32 zmm29, zmm25 vpermt2d zmm25, zmm27, zmm30 vpermt2d zmm29, zmm31, zmm30 vshufps zmm26, zmm9, zmm11, 136 vshufps zmm8, zmm13, zmm15, 136 vmovdqa32 zmm30, zmm26 vpermt2d zmm26, zmm27, zmm8 vpermt2d zmm30, zmm31, zmm8 vshufps zmm8, zmm9, zmm11, 221 vshufps zmm10, zmm13, zmm15, 221 vpermi2d zmm27, zmm8, zmm10 vpermi2d zmm31, zmm8, zmm10 vpbroadcastd zmm8, dword ptr [BLAKE3_IV_0] vpbroadcastd zmm9, dword ptr [BLAKE3_IV_1] vpbroadcastd zmm10, dword ptr [BLAKE3_IV_2] vpbroadcastd zmm11, dword ptr [BLAKE3_IV_3] vmovdqa32 zmm12, zmmword ptr [rsp] vmovdqa32 zmm13, zmmword ptr [rsp+1H*40H] vpbroadcastd zmm14, dword ptr [BLAKE3_BLOCK_LEN] vpbroadcastd zmm15, dword ptr [rsp+22H*4H] vpaddd zmm0, zmm0, zmm16 vpaddd zmm1, zmm1, zmm18 vpaddd zmm2, zmm2, zmm20 vpaddd zmm3, zmm3, zmm22 vpaddd zmm0, zmm0, zmm4 vpaddd zmm1, zmm1, zmm5 vpaddd zmm2, zmm2, zmm6 vpaddd zmm3, zmm3, zmm7 vpxord zmm12, zmm12, zmm0 vpxord zmm13, zmm13, zmm1 vpxord zmm14, zmm14, zmm2 vpxord zmm15, zmm15, zmm3 vprord zmm12, zmm12, 16 vprord zmm13, zmm13, 16 vprord zmm14, zmm14, 16 vprord zmm15, zmm15, 16 vpaddd zmm8, zmm8, zmm12 vpaddd zmm9, zmm9, zmm13 vpaddd zmm10, zmm10, zmm14 vpaddd zmm11, zmm11, zmm15 vpxord zmm4, zmm4, zmm8 vpxord zmm5, zmm5, zmm9 vpxord zmm6, zmm6, zmm10 vpxord zmm7, zmm7, zmm11 vprord zmm4, zmm4, 12 vprord zmm5, zmm5, 12 vprord zmm6, zmm6, 12 vprord zmm7, zmm7, 12 vpaddd zmm0, zmm0, zmm17 vpaddd zmm1, zmm1, zmm19 vpaddd zmm2, zmm2, zmm21 vpaddd zmm3, zmm3, zmm23 vpaddd zmm0, zmm0, zmm4 vpaddd zmm1, zmm1, zmm5 vpaddd zmm2, zmm2, zmm6 vpaddd zmm3, zmm3, zmm7 vpxord zmm12, zmm12, zmm0 vpxord zmm13, zmm13, zmm1 vpxord zmm14, zmm14, zmm2 vpxord zmm15, zmm15, zmm3 vprord zmm12, zmm12, 8 vprord zmm13, zmm13, 8 vprord zmm14, zmm14, 8 vprord zmm15, zmm15, 8 vpaddd zmm8, zmm8, zmm12 vpaddd zmm9, zmm9, zmm13 vpaddd zmm10, zmm10, zmm14 vpaddd zmm11, zmm11, zmm15 vpxord zmm4, zmm4, zmm8 vpxord zmm5, zmm5, zmm9 vpxord zmm6, zmm6, zmm10 vpxord zmm7, zmm7, zmm11 vprord zmm4, zmm4, 7 vprord zmm5, zmm5, 7 vprord zmm6, zmm6, 7 vprord zmm7, zmm7, 7 vpaddd zmm0, zmm0, zmm24 vpaddd zmm1, zmm1, zmm26 vpaddd zmm2, zmm2, zmm28 vpaddd zmm3, zmm3, zmm30 vpaddd zmm0, zmm0, zmm5 vpaddd zmm1, zmm1, zmm6 vpaddd zmm2, zmm2, zmm7 vpaddd zmm3, zmm3, zmm4 vpxord zmm15, zmm15, zmm0 vpxord zmm12, zmm12, zmm1 vpxord zmm13, zmm13, zmm2 vpxord zmm14, zmm14, zmm3 vprord zmm15, zmm15, 16 vprord zmm12, zmm12, 16 vprord zmm13, zmm13, 16 vprord zmm14, zmm14, 16 vpaddd zmm10, zmm10, zmm15 vpaddd zmm11, zmm11, zmm12 vpaddd zmm8, zmm8, zmm13 vpaddd zmm9, zmm9, zmm14 vpxord zmm5, zmm5, zmm10 vpxord zmm6, zmm6, zmm11 vpxord zmm7, zmm7, zmm8 vpxord zmm4, zmm4, zmm9 vprord zmm5, zmm5, 12 vprord zmm6, zmm6, 12 vprord zmm7, zmm7, 12 vprord zmm4, zmm4, 12 vpaddd zmm0, zmm0, zmm25 vpaddd zmm1, zmm1, zmm27 vpaddd zmm2, zmm2, zmm29 vpaddd zmm3, zmm3, zmm31 vpaddd zmm0, zmm0, zmm5 vpaddd zmm1, zmm1, zmm6 vpaddd zmm2, zmm2, zmm7 vpaddd zmm3, zmm3, zmm4 vpxord zmm15, zmm15, zmm0 vpxord zmm12, zmm12, zmm1 vpxord zmm13, zmm13, zmm2 vpxord zmm14, zmm14, zmm3 vprord zmm15, zmm15, 8 vprord zmm12, zmm12, 8 vprord zmm13, zmm13, 8 vprord zmm14, zmm14, 8 vpaddd zmm10, zmm10, zmm15 vpaddd zmm11, zmm11, zmm12 vpaddd zmm8, zmm8, zmm13 vpaddd zmm9, zmm9, zmm14 vpxord zmm5, zmm5, zmm10 vpxord zmm6, zmm6, zmm11 vpxord zmm7, zmm7, zmm8 vpxord zmm4, zmm4, zmm9 vprord zmm5, zmm5, 7 vprord zmm6, zmm6, 7 vprord zmm7, zmm7, 7 vprord zmm4, zmm4, 7 vpaddd zmm0, zmm0, zmm18 vpaddd zmm1, zmm1, zmm19 vpaddd zmm2, zmm2, zmm23 vpaddd zmm3, zmm3, zmm20 vpaddd zmm0, zmm0, zmm4 vpaddd zmm1, zmm1, zmm5 vpaddd zmm2, zmm2, zmm6 vpaddd zmm3, zmm3, zmm7 vpxord zmm12, zmm12, zmm0 vpxord zmm13, zmm13, zmm1 vpxord zmm14, zmm14, zmm2 vpxord zmm15, zmm15, zmm3 vprord zmm12, zmm12, 16 vprord zmm13, zmm13, 16 vprord zmm14, zmm14, 16 vprord zmm15, zmm15, 16 vpaddd zmm8, zmm8, zmm12 vpaddd zmm9, zmm9, zmm13 vpaddd zmm10, zmm10, zmm14 vpaddd zmm11, zmm11, zmm15 vpxord zmm4, zmm4, zmm8 vpxord zmm5, zmm5, zmm9 vpxord zmm6, zmm6, zmm10 vpxord zmm7, zmm7, zmm11 vprord zmm4, zmm4, 12 vprord zmm5, zmm5, 12 vprord zmm6, zmm6, 12 vprord zmm7, zmm7, 12 vpaddd zmm0, zmm0, zmm22 vpaddd zmm1, zmm1, zmm26 vpaddd zmm2, zmm2, zmm16 vpaddd zmm3, zmm3, zmm29 vpaddd zmm0, zmm0, zmm4 vpaddd zmm1, zmm1, zmm5 vpaddd zmm2, zmm2, zmm6 vpaddd zmm3, zmm3, zmm7 vpxord zmm12, zmm12, zmm0 vpxord zmm13, zmm13, zmm1 vpxord zmm14, zmm14, zmm2 vpxord zmm15, zmm15, zmm3 vprord zmm12, zmm12, 8 vprord zmm13, zmm13, 8 vprord zmm14, zmm14, 8 vprord zmm15, zmm15, 8 vpaddd zmm8, zmm8, zmm12 vpaddd zmm9, zmm9, zmm13 vpaddd zmm10, zmm10, zmm14 vpaddd zmm11, zmm11, zmm15 vpxord zmm4, zmm4, zmm8 vpxord zmm5, zmm5, zmm9 vpxord zmm6, zmm6, zmm10 vpxord zmm7, zmm7, zmm11 vprord zmm4, zmm4, 7 vprord zmm5, zmm5, 7 vprord zmm6, zmm6, 7 vprord zmm7, zmm7, 7 vpaddd zmm0, zmm0, zmm17 vpaddd zmm1, zmm1, zmm28 vpaddd zmm2, zmm2, zmm25 vpaddd zmm3, zmm3, zmm31 vpaddd zmm0, zmm0, zmm5 vpaddd zmm1, zmm1, zmm6 vpaddd zmm2, zmm2, zmm7 vpaddd zmm3, zmm3, zmm4 vpxord zmm15, zmm15, zmm0 vpxord zmm12, zmm12, zmm1 vpxord zmm13, zmm13, zmm2 vpxord zmm14, zmm14, zmm3 vprord zmm15, zmm15, 16 vprord zmm12, zmm12, 16 vprord zmm13, zmm13, 16 vprord zmm14, zmm14, 16 vpaddd zmm10, zmm10, zmm15 vpaddd zmm11, zmm11, zmm12 vpaddd zmm8, zmm8, zmm13 vpaddd zmm9, zmm9, zmm14 vpxord zmm5, zmm5, zmm10 vpxord zmm6, zmm6, zmm11 vpxord zmm7, zmm7, zmm8 vpxord zmm4, zmm4, zmm9 vprord zmm5, zmm5, 12 vprord zmm6, zmm6, 12 vprord zmm7, zmm7, 12 vprord zmm4, zmm4, 12 vpaddd zmm0, zmm0, zmm27 vpaddd zmm1, zmm1, zmm21 vpaddd zmm2, zmm2, zmm30 vpaddd zmm3, zmm3, zmm24 vpaddd zmm0, zmm0, zmm5 vpaddd zmm1, zmm1, zmm6 vpaddd zmm2, zmm2, zmm7 vpaddd zmm3, zmm3, zmm4 vpxord zmm15, zmm15, zmm0 vpxord zmm12, zmm12, zmm1 vpxord zmm13, zmm13, zmm2 vpxord zmm14, zmm14, zmm3 vprord zmm15, zmm15, 8 vprord zmm12, zmm12, 8 vprord zmm13, zmm13, 8 vprord zmm14, zmm14, 8 vpaddd zmm10, zmm10, zmm15 vpaddd zmm11, zmm11, zmm12 vpaddd zmm8, zmm8, zmm13 vpaddd zmm9, zmm9, zmm14 vpxord zmm5, zmm5, zmm10 vpxord zmm6, zmm6, zmm11 vpxord zmm7, zmm7, zmm8 vpxord zmm4, zmm4, zmm9 vprord zmm5, zmm5, 7 vprord zmm6, zmm6, 7 vprord zmm7, zmm7, 7 vprord zmm4, zmm4, 7 vpaddd zmm0, zmm0, zmm19 vpaddd zmm1, zmm1, zmm26 vpaddd zmm2, zmm2, zmm29 vpaddd zmm3, zmm3, zmm23 vpaddd zmm0, zmm0, zmm4 vpaddd zmm1, zmm1, zmm5 vpaddd zmm2, zmm2, zmm6 vpaddd zmm3, zmm3, zmm7 vpxord zmm12, zmm12, zmm0 vpxord zmm13, zmm13, zmm1 vpxord zmm14, zmm14, zmm2 vpxord zmm15, zmm15, zmm3 vprord zmm12, zmm12, 16 vprord zmm13, zmm13, 16 vprord zmm14, zmm14, 16 vprord zmm15, zmm15, 16 vpaddd zmm8, zmm8, zmm12 vpaddd zmm9, zmm9, zmm13 vpaddd zmm10, zmm10, zmm14 vpaddd zmm11, zmm11, zmm15 vpxord zmm4, zmm4, zmm8 vpxord zmm5, zmm5, zmm9 vpxord zmm6, zmm6, zmm10 vpxord zmm7, zmm7, zmm11 vprord zmm4, zmm4, 12 vprord zmm5, zmm5, 12 vprord zmm6, zmm6, 12 vprord zmm7, zmm7, 12 vpaddd zmm0, zmm0, zmm20 vpaddd zmm1, zmm1, zmm28 vpaddd zmm2, zmm2, zmm18 vpaddd zmm3, zmm3, zmm30 vpaddd zmm0, zmm0, zmm4 vpaddd zmm1, zmm1, zmm5 vpaddd zmm2, zmm2, zmm6 vpaddd zmm3, zmm3, zmm7 vpxord zmm12, zmm12, zmm0 vpxord zmm13, zmm13, zmm1 vpxord zmm14, zmm14, zmm2 vpxord zmm15, zmm15, zmm3 vprord zmm12, zmm12, 8 vprord zmm13, zmm13, 8 vprord zmm14, zmm14, 8 vprord zmm15, zmm15, 8 vpaddd zmm8, zmm8, zmm12 vpaddd zmm9, zmm9, zmm13 vpaddd zmm10, zmm10, zmm14 vpaddd zmm11, zmm11, zmm15 vpxord zmm4, zmm4, zmm8 vpxord zmm5, zmm5, zmm9 vpxord zmm6, zmm6, zmm10 vpxord zmm7, zmm7, zmm11 vprord zmm4, zmm4, 7 vprord zmm5, zmm5, 7 vprord zmm6, zmm6, 7 vprord zmm7, zmm7, 7 vpaddd zmm0, zmm0, zmm22 vpaddd zmm1, zmm1, zmm25 vpaddd zmm2, zmm2, zmm27 vpaddd zmm3, zmm3, zmm24 vpaddd zmm0, zmm0, zmm5 vpaddd zmm1, zmm1, zmm6 vpaddd zmm2, zmm2, zmm7 vpaddd zmm3, zmm3, zmm4 vpxord zmm15, zmm15, zmm0 vpxord zmm12, zmm12, zmm1 vpxord zmm13, zmm13, zmm2 vpxord zmm14, zmm14, zmm3 vprord zmm15, zmm15, 16 vprord zmm12, zmm12, 16 vprord zmm13, zmm13, 16 vprord zmm14, zmm14, 16 vpaddd zmm10, zmm10, zmm15 vpaddd zmm11, zmm11, zmm12 vpaddd zmm8, zmm8, zmm13 vpaddd zmm9, zmm9, zmm14 vpxord zmm5, zmm5, zmm10 vpxord zmm6, zmm6, zmm11 vpxord zmm7, zmm7, zmm8 vpxord zmm4, zmm4, zmm9 vprord zmm5, zmm5, 12 vprord zmm6, zmm6, 12 vprord zmm7, zmm7, 12 vprord zmm4, zmm4, 12 vpaddd zmm0, zmm0, zmm21 vpaddd zmm1, zmm1, zmm16 vpaddd zmm2, zmm2, zmm31 vpaddd zmm3, zmm3, zmm17 vpaddd zmm0, zmm0, zmm5 vpaddd zmm1, zmm1, zmm6 vpaddd zmm2, zmm2, zmm7 vpaddd zmm3, zmm3, zmm4 vpxord zmm15, zmm15, zmm0 vpxord zmm12, zmm12, zmm1 vpxord zmm13, zmm13, zmm2 vpxord zmm14, zmm14, zmm3 vprord zmm15, zmm15, 8 vprord zmm12, zmm12, 8 vprord zmm13, zmm13, 8 vprord zmm14, zmm14, 8 vpaddd zmm10, zmm10, zmm15 vpaddd zmm11, zmm11, zmm12 vpaddd zmm8, zmm8, zmm13 vpaddd zmm9, zmm9, zmm14 vpxord zmm5, zmm5, zmm10 vpxord zmm6, zmm6, zmm11 vpxord zmm7, zmm7, zmm8 vpxord zmm4, zmm4, zmm9 vprord zmm5, zmm5, 7 vprord zmm6, zmm6, 7 vprord zmm7, zmm7, 7 vprord zmm4, zmm4, 7 vpaddd zmm0, zmm0, zmm26 vpaddd zmm1, zmm1, zmm28 vpaddd zmm2, zmm2, zmm30 vpaddd zmm3, zmm3, zmm29 vpaddd zmm0, zmm0, zmm4 vpaddd zmm1, zmm1, zmm5 vpaddd zmm2, zmm2, zmm6 vpaddd zmm3, zmm3, zmm7 vpxord zmm12, zmm12, zmm0 vpxord zmm13, zmm13, zmm1 vpxord zmm14, zmm14, zmm2 vpxord zmm15, zmm15, zmm3 vprord zmm12, zmm12, 16 vprord zmm13, zmm13, 16 vprord zmm14, zmm14, 16 vprord zmm15, zmm15, 16 vpaddd zmm8, zmm8, zmm12 vpaddd zmm9, zmm9, zmm13 vpaddd zmm10, zmm10, zmm14 vpaddd zmm11, zmm11, zmm15 vpxord zmm4, zmm4, zmm8 vpxord zmm5, zmm5, zmm9 vpxord zmm6, zmm6, zmm10 vpxord zmm7, zmm7, zmm11 vprord zmm4, zmm4, 12 vprord zmm5, zmm5, 12 vprord zmm6, zmm6, 12 vprord zmm7, zmm7, 12 vpaddd zmm0, zmm0, zmm23 vpaddd zmm1, zmm1, zmm25 vpaddd zmm2, zmm2, zmm19 vpaddd zmm3, zmm3, zmm31 vpaddd zmm0, zmm0, zmm4 vpaddd zmm1, zmm1, zmm5 vpaddd zmm2, zmm2, zmm6 vpaddd zmm3, zmm3, zmm7 vpxord zmm12, zmm12, zmm0 vpxord zmm13, zmm13, zmm1 vpxord zmm14, zmm14, zmm2 vpxord zmm15, zmm15, zmm3 vprord zmm12, zmm12, 8 vprord zmm13, zmm13, 8 vprord zmm14, zmm14, 8 vprord zmm15, zmm15, 8 vpaddd zmm8, zmm8, zmm12 vpaddd zmm9, zmm9, zmm13 vpaddd zmm10, zmm10, zmm14 vpaddd zmm11, zmm11, zmm15 vpxord zmm4, zmm4, zmm8 vpxord zmm5, zmm5, zmm9 vpxord zmm6, zmm6, zmm10 vpxord zmm7, zmm7, zmm11 vprord zmm4, zmm4, 7 vprord zmm5, zmm5, 7 vprord zmm6, zmm6, 7 vprord zmm7, zmm7, 7 vpaddd zmm0, zmm0, zmm20 vpaddd zmm1, zmm1, zmm27 vpaddd zmm2, zmm2, zmm21 vpaddd zmm3, zmm3, zmm17 vpaddd zmm0, zmm0, zmm5 vpaddd zmm1, zmm1, zmm6 vpaddd zmm2, zmm2, zmm7 vpaddd zmm3, zmm3, zmm4 vpxord zmm15, zmm15, zmm0 vpxord zmm12, zmm12, zmm1 vpxord zmm13, zmm13, zmm2 vpxord zmm14, zmm14, zmm3 vprord zmm15, zmm15, 16 vprord zmm12, zmm12, 16 vprord zmm13, zmm13, 16 vprord zmm14, zmm14, 16 vpaddd zmm10, zmm10, zmm15 vpaddd zmm11, zmm11, zmm12 vpaddd zmm8, zmm8, zmm13 vpaddd zmm9, zmm9, zmm14 vpxord zmm5, zmm5, zmm10 vpxord zmm6, zmm6, zmm11 vpxord zmm7, zmm7, zmm8 vpxord zmm4, zmm4, zmm9 vprord zmm5, zmm5, 12 vprord zmm6, zmm6, 12 vprord zmm7, zmm7, 12 vprord zmm4, zmm4, 12 vpaddd zmm0, zmm0, zmm16 vpaddd zmm1, zmm1, zmm18 vpaddd zmm2, zmm2, zmm24 vpaddd zmm3, zmm3, zmm22 vpaddd zmm0, zmm0, zmm5 vpaddd zmm1, zmm1, zmm6 vpaddd zmm2, zmm2, zmm7 vpaddd zmm3, zmm3, zmm4 vpxord zmm15, zmm15, zmm0 vpxord zmm12, zmm12, zmm1 vpxord zmm13, zmm13, zmm2 vpxord zmm14, zmm14, zmm3 vprord zmm15, zmm15, 8 vprord zmm12, zmm12, 8 vprord zmm13, zmm13, 8 vprord zmm14, zmm14, 8 vpaddd zmm10, zmm10, zmm15 vpaddd zmm11, zmm11, zmm12 vpaddd zmm8, zmm8, zmm13 vpaddd zmm9, zmm9, zmm14 vpxord zmm5, zmm5, zmm10 vpxord zmm6, zmm6, zmm11 vpxord zmm7, zmm7, zmm8 vpxord zmm4, zmm4, zmm9 vprord zmm5, zmm5, 7 vprord zmm6, zmm6, 7 vprord zmm7, zmm7, 7 vprord zmm4, zmm4, 7 vpaddd zmm0, zmm0, zmm28 vpaddd zmm1, zmm1, zmm25 vpaddd zmm2, zmm2, zmm31 vpaddd zmm3, zmm3, zmm30 vpaddd zmm0, zmm0, zmm4 vpaddd zmm1, zmm1, zmm5 vpaddd zmm2, zmm2, zmm6 vpaddd zmm3, zmm3, zmm7 vpxord zmm12, zmm12, zmm0 vpxord zmm13, zmm13, zmm1 vpxord zmm14, zmm14, zmm2 vpxord zmm15, zmm15, zmm3 vprord zmm12, zmm12, 16 vprord zmm13, zmm13, 16 vprord zmm14, zmm14, 16 vprord zmm15, zmm15, 16 vpaddd zmm8, zmm8, zmm12 vpaddd zmm9, zmm9, zmm13 vpaddd zmm10, zmm10, zmm14 vpaddd zmm11, zmm11, zmm15 vpxord zmm4, zmm4, zmm8 vpxord zmm5, zmm5, zmm9 vpxord zmm6, zmm6, zmm10 vpxord zmm7, zmm7, zmm11 vprord zmm4, zmm4, 12 vprord zmm5, zmm5, 12 vprord zmm6, zmm6, 12 vprord zmm7, zmm7, 12 vpaddd zmm0, zmm0, zmm29 vpaddd zmm1, zmm1, zmm27 vpaddd zmm2, zmm2, zmm26 vpaddd zmm3, zmm3, zmm24 vpaddd zmm0, zmm0, zmm4 vpaddd zmm1, zmm1, zmm5 vpaddd zmm2, zmm2, zmm6 vpaddd zmm3, zmm3, zmm7 vpxord zmm12, zmm12, zmm0 vpxord zmm13, zmm13, zmm1 vpxord zmm14, zmm14, zmm2 vpxord zmm15, zmm15, zmm3 vprord zmm12, zmm12, 8 vprord zmm13, zmm13, 8 vprord zmm14, zmm14, 8 vprord zmm15, zmm15, 8 vpaddd zmm8, zmm8, zmm12 vpaddd zmm9, zmm9, zmm13 vpaddd zmm10, zmm10, zmm14 vpaddd zmm11, zmm11, zmm15 vpxord zmm4, zmm4, zmm8 vpxord zmm5, zmm5, zmm9 vpxord zmm6, zmm6, zmm10 vpxord zmm7, zmm7, zmm11 vprord zmm4, zmm4, 7 vprord zmm5, zmm5, 7 vprord zmm6, zmm6, 7 vprord zmm7, zmm7, 7 vpaddd zmm0, zmm0, zmm23 vpaddd zmm1, zmm1, zmm21 vpaddd zmm2, zmm2, zmm16 vpaddd zmm3, zmm3, zmm22 vpaddd zmm0, zmm0, zmm5 vpaddd zmm1, zmm1, zmm6 vpaddd zmm2, zmm2, zmm7 vpaddd zmm3, zmm3, zmm4 vpxord zmm15, zmm15, zmm0 vpxord zmm12, zmm12, zmm1 vpxord zmm13, zmm13, zmm2 vpxord zmm14, zmm14, zmm3 vprord zmm15, zmm15, 16 vprord zmm12, zmm12, 16 vprord zmm13, zmm13, 16 vprord zmm14, zmm14, 16 vpaddd zmm10, zmm10, zmm15 vpaddd zmm11, zmm11, zmm12 vpaddd zmm8, zmm8, zmm13 vpaddd zmm9, zmm9, zmm14 vpxord zmm5, zmm5, zmm10 vpxord zmm6, zmm6, zmm11 vpxord zmm7, zmm7, zmm8 vpxord zmm4, zmm4, zmm9 vprord zmm5, zmm5, 12 vprord zmm6, zmm6, 12 vprord zmm7, zmm7, 12 vprord zmm4, zmm4, 12 vpaddd zmm0, zmm0, zmm18 vpaddd zmm1, zmm1, zmm19 vpaddd zmm2, zmm2, zmm17 vpaddd zmm3, zmm3, zmm20 vpaddd zmm0, zmm0, zmm5 vpaddd zmm1, zmm1, zmm6 vpaddd zmm2, zmm2, zmm7 vpaddd zmm3, zmm3, zmm4 vpxord zmm15, zmm15, zmm0 vpxord zmm12, zmm12, zmm1 vpxord zmm13, zmm13, zmm2 vpxord zmm14, zmm14, zmm3 vprord zmm15, zmm15, 8 vprord zmm12, zmm12, 8 vprord zmm13, zmm13, 8 vprord zmm14, zmm14, 8 vpaddd zmm10, zmm10, zmm15 vpaddd zmm11, zmm11, zmm12 vpaddd zmm8, zmm8, zmm13 vpaddd zmm9, zmm9, zmm14 vpxord zmm5, zmm5, zmm10 vpxord zmm6, zmm6, zmm11 vpxord zmm7, zmm7, zmm8 vpxord zmm4, zmm4, zmm9 vprord zmm5, zmm5, 7 vprord zmm6, zmm6, 7 vprord zmm7, zmm7, 7 vprord zmm4, zmm4, 7 vpaddd zmm0, zmm0, zmm25 vpaddd zmm1, zmm1, zmm27 vpaddd zmm2, zmm2, zmm24 vpaddd zmm3, zmm3, zmm31 vpaddd zmm0, zmm0, zmm4 vpaddd zmm1, zmm1, zmm5 vpaddd zmm2, zmm2, zmm6 vpaddd zmm3, zmm3, zmm7 vpxord zmm12, zmm12, zmm0 vpxord zmm13, zmm13, zmm1 vpxord zmm14, zmm14, zmm2 vpxord zmm15, zmm15, zmm3 vprord zmm12, zmm12, 16 vprord zmm13, zmm13, 16 vprord zmm14, zmm14, 16 vprord zmm15, zmm15, 16 vpaddd zmm8, zmm8, zmm12 vpaddd zmm9, zmm9, zmm13 vpaddd zmm10, zmm10, zmm14 vpaddd zmm11, zmm11, zmm15 vpxord zmm4, zmm4, zmm8 vpxord zmm5, zmm5, zmm9 vpxord zmm6, zmm6, zmm10 vpxord zmm7, zmm7, zmm11 vprord zmm4, zmm4, 12 vprord zmm5, zmm5, 12 vprord zmm6, zmm6, 12 vprord zmm7, zmm7, 12 vpaddd zmm0, zmm0, zmm30 vpaddd zmm1, zmm1, zmm21 vpaddd zmm2, zmm2, zmm28 vpaddd zmm3, zmm3, zmm17 vpaddd zmm0, zmm0, zmm4 vpaddd zmm1, zmm1, zmm5 vpaddd zmm2, zmm2, zmm6 vpaddd zmm3, zmm3, zmm7 vpxord zmm12, zmm12, zmm0 vpxord zmm13, zmm13, zmm1 vpxord zmm14, zmm14, zmm2 vpxord zmm15, zmm15, zmm3 vprord zmm12, zmm12, 8 vprord zmm13, zmm13, 8 vprord zmm14, zmm14, 8 vprord zmm15, zmm15, 8 vpaddd zmm8, zmm8, zmm12 vpaddd zmm9, zmm9, zmm13 vpaddd zmm10, zmm10, zmm14 vpaddd zmm11, zmm11, zmm15 vpxord zmm4, zmm4, zmm8 vpxord zmm5, zmm5, zmm9 vpxord zmm6, zmm6, zmm10 vpxord zmm7, zmm7, zmm11 vprord zmm4, zmm4, 7 vprord zmm5, zmm5, 7 vprord zmm6, zmm6, 7 vprord zmm7, zmm7, 7 vpaddd zmm0, zmm0, zmm29 vpaddd zmm1, zmm1, zmm16 vpaddd zmm2, zmm2, zmm18 vpaddd zmm3, zmm3, zmm20 vpaddd zmm0, zmm0, zmm5 vpaddd zmm1, zmm1, zmm6 vpaddd zmm2, zmm2, zmm7 vpaddd zmm3, zmm3, zmm4 vpxord zmm15, zmm15, zmm0 vpxord zmm12, zmm12, zmm1 vpxord zmm13, zmm13, zmm2 vpxord zmm14, zmm14, zmm3 vprord zmm15, zmm15, 16 vprord zmm12, zmm12, 16 vprord zmm13, zmm13, 16 vprord zmm14, zmm14, 16 vpaddd zmm10, zmm10, zmm15 vpaddd zmm11, zmm11, zmm12 vpaddd zmm8, zmm8, zmm13 vpaddd zmm9, zmm9, zmm14 vpxord zmm5, zmm5, zmm10 vpxord zmm6, zmm6, zmm11 vpxord zmm7, zmm7, zmm8 vpxord zmm4, zmm4, zmm9 vprord zmm5, zmm5, 12 vprord zmm6, zmm6, 12 vprord zmm7, zmm7, 12 vprord zmm4, zmm4, 12 vpaddd zmm0, zmm0, zmm19 vpaddd zmm1, zmm1, zmm26 vpaddd zmm2, zmm2, zmm22 vpaddd zmm3, zmm3, zmm23 vpaddd zmm0, zmm0, zmm5 vpaddd zmm1, zmm1, zmm6 vpaddd zmm2, zmm2, zmm7 vpaddd zmm3, zmm3, zmm4 vpxord zmm15, zmm15, zmm0 vpxord zmm12, zmm12, zmm1 vpxord zmm13, zmm13, zmm2 vpxord zmm14, zmm14, zmm3 vprord zmm15, zmm15, 8 vprord zmm12, zmm12, 8 vprord zmm13, zmm13, 8 vprord zmm14, zmm14, 8 vpaddd zmm10, zmm10, zmm15 vpaddd zmm11, zmm11, zmm12 vpaddd zmm8, zmm8, zmm13 vpaddd zmm9, zmm9, zmm14 vpxord zmm5, zmm5, zmm10 vpxord zmm6, zmm6, zmm11 vpxord zmm7, zmm7, zmm8 vpxord zmm4, zmm4, zmm9 vprord zmm5, zmm5, 7 vprord zmm6, zmm6, 7 vprord zmm7, zmm7, 7 vprord zmm4, zmm4, 7 vpaddd zmm0, zmm0, zmm27 vpaddd zmm1, zmm1, zmm21 vpaddd zmm2, zmm2, zmm17 vpaddd zmm3, zmm3, zmm24 vpaddd zmm0, zmm0, zmm4 vpaddd zmm1, zmm1, zmm5 vpaddd zmm2, zmm2, zmm6 vpaddd zmm3, zmm3, zmm7 vpxord zmm12, zmm12, zmm0 vpxord zmm13, zmm13, zmm1 vpxord zmm14, zmm14, zmm2 vpxord zmm15, zmm15, zmm3 vprord zmm12, zmm12, 16 vprord zmm13, zmm13, 16 vprord zmm14, zmm14, 16 vprord zmm15, zmm15, 16 vpaddd zmm8, zmm8, zmm12 vpaddd zmm9, zmm9, zmm13 vpaddd zmm10, zmm10, zmm14 vpaddd zmm11, zmm11, zmm15 vpxord zmm4, zmm4, zmm8 vpxord zmm5, zmm5, zmm9 vpxord zmm6, zmm6, zmm10 vpxord zmm7, zmm7, zmm11 vprord zmm4, zmm4, 12 vprord zmm5, zmm5, 12 vprord zmm6, zmm6, 12 vprord zmm7, zmm7, 12 vpaddd zmm0, zmm0, zmm31 vpaddd zmm1, zmm1, zmm16 vpaddd zmm2, zmm2, zmm25 vpaddd zmm3, zmm3, zmm22 vpaddd zmm0, zmm0, zmm4 vpaddd zmm1, zmm1, zmm5 vpaddd zmm2, zmm2, zmm6 vpaddd zmm3, zmm3, zmm7 vpxord zmm12, zmm12, zmm0 vpxord zmm13, zmm13, zmm1 vpxord zmm14, zmm14, zmm2 vpxord zmm15, zmm15, zmm3 vprord zmm12, zmm12, 8 vprord zmm13, zmm13, 8 vprord zmm14, zmm14, 8 vprord zmm15, zmm15, 8 vpaddd zmm8, zmm8, zmm12 vpaddd zmm9, zmm9, zmm13 vpaddd zmm10, zmm10, zmm14 vpaddd zmm11, zmm11, zmm15 vpxord zmm4, zmm4, zmm8 vpxord zmm5, zmm5, zmm9 vpxord zmm6, zmm6, zmm10 vpxord zmm7, zmm7, zmm11 vprord zmm4, zmm4, 7 vprord zmm5, zmm5, 7 vprord zmm6, zmm6, 7 vprord zmm7, zmm7, 7 vpaddd zmm0, zmm0, zmm30 vpaddd zmm1, zmm1, zmm18 vpaddd zmm2, zmm2, zmm19 vpaddd zmm3, zmm3, zmm23 vpaddd zmm0, zmm0, zmm5 vpaddd zmm1, zmm1, zmm6 vpaddd zmm2, zmm2, zmm7 vpaddd zmm3, zmm3, zmm4 vpxord zmm15, zmm15, zmm0 vpxord zmm12, zmm12, zmm1 vpxord zmm13, zmm13, zmm2 vpxord zmm14, zmm14, zmm3 vprord zmm15, zmm15, 16 vprord zmm12, zmm12, 16 vprord zmm13, zmm13, 16 vprord zmm14, zmm14, 16 vpaddd zmm10, zmm10, zmm15 vpaddd zmm11, zmm11, zmm12 vpaddd zmm8, zmm8, zmm13 vpaddd zmm9, zmm9, zmm14 vpxord zmm5, zmm5, zmm10 vpxord zmm6, zmm6, zmm11 vpxord zmm7, zmm7, zmm8 vpxord zmm4, zmm4, zmm9 vprord zmm5, zmm5, 12 vprord zmm6, zmm6, 12 vprord zmm7, zmm7, 12 vprord zmm4, zmm4, 12 vpaddd zmm0, zmm0, zmm26 vpaddd zmm1, zmm1, zmm28 vpaddd zmm2, zmm2, zmm20 vpaddd zmm3, zmm3, zmm29 vpaddd zmm0, zmm0, zmm5 vpaddd zmm1, zmm1, zmm6 vpaddd zmm2, zmm2, zmm7 vpaddd zmm3, zmm3, zmm4 vpxord zmm15, zmm15, zmm0 vpxord zmm12, zmm12, zmm1 vpxord zmm13, zmm13, zmm2 vpxord zmm14, zmm14, zmm3 vprord zmm15, zmm15, 8 vprord zmm12, zmm12, 8 vprord zmm13, zmm13, 8 vprord zmm14, zmm14, 8 vpaddd zmm10, zmm10, zmm15 vpaddd zmm11, zmm11, zmm12 vpaddd zmm8, zmm8, zmm13 vpaddd zmm9, zmm9, zmm14 vpxord zmm5, zmm5, zmm10 vpxord zmm6, zmm6, zmm11 vpxord zmm7, zmm7, zmm8 vpxord zmm4, zmm4, zmm9 vprord zmm5, zmm5, 7 vprord zmm6, zmm6, 7 vprord zmm7, zmm7, 7 vprord zmm4, zmm4, 7 vpxord zmm0, zmm0, zmm8 vpxord zmm1, zmm1, zmm9 vpxord zmm2, zmm2, zmm10 vpxord zmm3, zmm3, zmm11 vpxord zmm4, zmm4, zmm12 vpxord zmm5, zmm5, zmm13 vpxord zmm6, zmm6, zmm14 vpxord zmm7, zmm7, zmm15 movzx eax, byte ptr [rbp+78H] jne innerloop16 mov rbx, qword ptr [rbp+90H] vpunpckldq zmm16, zmm0, zmm1 vpunpckhdq zmm17, zmm0, zmm1 vpunpckldq zmm18, zmm2, zmm3 vpunpckhdq zmm19, zmm2, zmm3 vpunpckldq zmm20, zmm4, zmm5 vpunpckhdq zmm21, zmm4, zmm5 vpunpckldq zmm22, zmm6, zmm7 vpunpckhdq zmm23, zmm6, zmm7 vpunpcklqdq zmm0, zmm16, zmm18 vpunpckhqdq zmm1, zmm16, zmm18 vpunpcklqdq zmm2, zmm17, zmm19 vpunpckhqdq zmm3, zmm17, zmm19 vpunpcklqdq zmm4, zmm20, zmm22 vpunpckhqdq zmm5, zmm20, zmm22 vpunpcklqdq zmm6, zmm21, zmm23 vpunpckhqdq zmm7, zmm21, zmm23 vshufi32x4 zmm16, zmm0, zmm4, 88H vshufi32x4 zmm17, zmm1, zmm5, 88H vshufi32x4 zmm18, zmm2, zmm6, 88H vshufi32x4 zmm19, zmm3, zmm7, 88H vshufi32x4 zmm20, zmm0, zmm4, 0DDH vshufi32x4 zmm21, zmm1, zmm5, 0DDH vshufi32x4 zmm22, zmm2, zmm6, 0DDH vshufi32x4 zmm23, zmm3, zmm7, 0DDH vshufi32x4 zmm0, zmm16, zmm17, 88H vshufi32x4 zmm1, zmm18, zmm19, 88H vshufi32x4 zmm2, zmm20, zmm21, 88H vshufi32x4 zmm3, zmm22, zmm23, 88H vshufi32x4 zmm4, zmm16, zmm17, 0DDH vshufi32x4 zmm5, zmm18, zmm19, 0DDH vshufi32x4 zmm6, zmm20, zmm21, 0DDH vshufi32x4 zmm7, zmm22, zmm23, 0DDH vmovdqu32 zmmword ptr [rbx], zmm0 vmovdqu32 zmmword ptr [rbx+1H*40H], zmm1 vmovdqu32 zmmword ptr [rbx+2H*40H], zmm2 vmovdqu32 zmmword ptr [rbx+3H*40H], zmm3 vmovdqu32 zmmword ptr [rbx+4H*40H], zmm4 vmovdqu32 zmmword ptr [rbx+5H*40H], zmm5 vmovdqu32 zmmword ptr [rbx+6H*40H], zmm6 vmovdqu32 zmmword ptr [rbx+7H*40H], zmm7 vmovdqa32 zmm0, zmmword ptr [rsp] vmovdqa32 zmm1, zmmword ptr [rsp+1H*40H] vmovdqa32 zmm2, zmm0 ; XXX: ml64.exe does not currently understand the syntax. We use a workaround. vpbroadcastd zmm4, dword ptr [ADD16] vpbroadcastd zmm5, dword ptr [ADD1] vpaddd zmm2{k1}, zmm0, zmm4 ; vpaddd zmm2{k1}, zmm0, dword ptr [ADD16] ; {1to16} vpcmpud k2, zmm2, zmm0, 1 vpaddd zmm1 {k2}, zmm1, zmm5 ; vpaddd zmm1 {k2}, zmm1, dword ptr [ADD1] ; {1to16} vmovdqa32 zmmword ptr [rsp], zmm2 vmovdqa32 zmmword ptr [rsp+1H*40H], zmm1 add rdi, 128 add rbx, 512 mov qword ptr [rbp+90H], rbx sub rsi, 16 cmp rsi, 16 jnc outerloop16 test rsi, rsi jne final15blocks unwind: vzeroupper vmovdqa xmm6, xmmword ptr [rsp+90H] vmovdqa xmm7, xmmword ptr [rsp+0A0H] vmovdqa xmm8, xmmword ptr [rsp+0B0H] vmovdqa xmm9, xmmword ptr [rsp+0C0H] vmovdqa xmm10, xmmword ptr [rsp+0D0H] vmovdqa xmm11, xmmword ptr [rsp+0E0H] vmovdqa xmm12, xmmword ptr [rsp+0F0H] vmovdqa xmm13, xmmword ptr [rsp+100H] vmovdqa xmm14, xmmword ptr [rsp+110H] vmovdqa xmm15, xmmword ptr [rsp+120H] mov rsp, rbp pop rbp pop rbx pop rsi pop rdi pop r12 pop r13 pop r14 pop r15 ret ALIGN 16 final15blocks: test esi, 8H je final7blocks vpbroadcastd ymm0, dword ptr [rcx] vpbroadcastd ymm1, dword ptr [rcx+4H] vpbroadcastd ymm2, dword ptr [rcx+8H] vpbroadcastd ymm3, dword ptr [rcx+0CH] vpbroadcastd ymm4, dword ptr [rcx+10H] vpbroadcastd ymm5, dword ptr [rcx+14H] vpbroadcastd ymm6, dword ptr [rcx+18H] vpbroadcastd ymm7, dword ptr [rcx+1CH] mov r8, qword ptr [rdi] mov r9, qword ptr [rdi+8H] mov r10, qword ptr [rdi+10H] mov r11, qword ptr [rdi+18H] mov r12, qword ptr [rdi+20H] mov r13, qword ptr [rdi+28H] mov r14, qword ptr [rdi+30H] mov r15, qword ptr [rdi+38H] movzx eax, byte ptr [rbp+78H] movzx ebx, byte ptr [rbp+80H] or eax, ebx xor edx, edx innerloop8: movzx ebx, byte ptr [rbp+88H] or ebx, eax add rdx, 64 cmp rdx, qword ptr [rsp+80H] cmove eax, ebx mov dword ptr [rsp+88H], eax vmovups xmm8, xmmword ptr [r8+rdx-40H] vinsertf128 ymm8, ymm8, xmmword ptr [r12+rdx-40H], 01H vmovups xmm9, xmmword ptr [r9+rdx-40H] vinsertf128 ymm9, ymm9, xmmword ptr [r13+rdx-40H], 01H vunpcklpd ymm12, ymm8, ymm9 vunpckhpd ymm13, ymm8, ymm9 vmovups xmm10, xmmword ptr [r10+rdx-40H] vinsertf128 ymm10, ymm10, xmmword ptr [r14+rdx-40H], 01H vmovups xmm11, xmmword ptr [r11+rdx-40H] vinsertf128 ymm11, ymm11, xmmword ptr [r15+rdx-40H], 01H vunpcklpd ymm14, ymm10, ymm11 vunpckhpd ymm15, ymm10, ymm11 vshufps ymm16, ymm12, ymm14, 136 vshufps ymm17, ymm12, ymm14, 221 vshufps ymm18, ymm13, ymm15, 136 vshufps ymm19, ymm13, ymm15, 221 vmovups xmm8, xmmword ptr [r8+rdx-30H] vinsertf128 ymm8, ymm8, xmmword ptr [r12+rdx-30H], 01H vmovups xmm9, xmmword ptr [r9+rdx-30H] vinsertf128 ymm9, ymm9, xmmword ptr [r13+rdx-30H], 01H vunpcklpd ymm12, ymm8, ymm9 vunpckhpd ymm13, ymm8, ymm9 vmovups xmm10, xmmword ptr [r10+rdx-30H] vinsertf128 ymm10, ymm10, xmmword ptr [r14+rdx-30H], 01H vmovups xmm11, xmmword ptr [r11+rdx-30H] vinsertf128 ymm11, ymm11, xmmword ptr [r15+rdx-30H], 01H vunpcklpd ymm14, ymm10, ymm11 vunpckhpd ymm15, ymm10, ymm11 vshufps ymm20, ymm12, ymm14, 136 vshufps ymm21, ymm12, ymm14, 221 vshufps ymm22, ymm13, ymm15, 136 vshufps ymm23, ymm13, ymm15, 221 vmovups xmm8, xmmword ptr [r8+rdx-20H] vinsertf128 ymm8, ymm8, xmmword ptr [r12+rdx-20H], 01H vmovups xmm9, xmmword ptr [r9+rdx-20H] vinsertf128 ymm9, ymm9, xmmword ptr [r13+rdx-20H], 01H vunpcklpd ymm12, ymm8, ymm9 vunpckhpd ymm13, ymm8, ymm9 vmovups xmm10, xmmword ptr [r10+rdx-20H] vinsertf128 ymm10, ymm10, xmmword ptr [r14+rdx-20H], 01H vmovups xmm11, xmmword ptr [r11+rdx-20H] vinsertf128 ymm11, ymm11, xmmword ptr [r15+rdx-20H], 01H vunpcklpd ymm14, ymm10, ymm11 vunpckhpd ymm15, ymm10, ymm11 vshufps ymm24, ymm12, ymm14, 136 vshufps ymm25, ymm12, ymm14, 221 vshufps ymm26, ymm13, ymm15, 136 vshufps ymm27, ymm13, ymm15, 221 vmovups xmm8, xmmword ptr [r8+rdx-10H] vinsertf128 ymm8, ymm8, xmmword ptr [r12+rdx-10H], 01H vmovups xmm9, xmmword ptr [r9+rdx-10H] vinsertf128 ymm9, ymm9, xmmword ptr [r13+rdx-10H], 01H vunpcklpd ymm12, ymm8, ymm9 vunpckhpd ymm13, ymm8, ymm9 vmovups xmm10, xmmword ptr [r10+rdx-10H] vinsertf128 ymm10, ymm10, xmmword ptr [r14+rdx-10H], 01H vmovups xmm11, xmmword ptr [r11+rdx-10H] vinsertf128 ymm11, ymm11, xmmword ptr [r15+rdx-10H], 01H vunpcklpd ymm14, ymm10, ymm11 vunpckhpd ymm15, ymm10, ymm11 vshufps ymm28, ymm12, ymm14, 136 vshufps ymm29, ymm12, ymm14, 221 vshufps ymm30, ymm13, ymm15, 136 vshufps ymm31, ymm13, ymm15, 221 vpbroadcastd ymm8, dword ptr [BLAKE3_IV_0] vpbroadcastd ymm9, dword ptr [BLAKE3_IV_1] vpbroadcastd ymm10, dword ptr [BLAKE3_IV_2] vpbroadcastd ymm11, dword ptr [BLAKE3_IV_3] vmovdqa ymm12, ymmword ptr [rsp] vmovdqa ymm13, ymmword ptr [rsp+40H] vpbroadcastd ymm14, dword ptr [BLAKE3_BLOCK_LEN] vpbroadcastd ymm15, dword ptr [rsp+88H] vpaddd ymm0, ymm0, ymm16 vpaddd ymm1, ymm1, ymm18 vpaddd ymm2, ymm2, ymm20 vpaddd ymm3, ymm3, ymm22 vpaddd ymm0, ymm0, ymm4 vpaddd ymm1, ymm1, ymm5 vpaddd ymm2, ymm2, ymm6 vpaddd ymm3, ymm3, ymm7 vpxord ymm12, ymm12, ymm0 vpxord ymm13, ymm13, ymm1 vpxord ymm14, ymm14, ymm2 vpxord ymm15, ymm15, ymm3 vprord ymm12, ymm12, 16 vprord ymm13, ymm13, 16 vprord ymm14, ymm14, 16 vprord ymm15, ymm15, 16 vpaddd ymm8, ymm8, ymm12 vpaddd ymm9, ymm9, ymm13 vpaddd ymm10, ymm10, ymm14 vpaddd ymm11, ymm11, ymm15 vpxord ymm4, ymm4, ymm8 vpxord ymm5, ymm5, ymm9 vpxord ymm6, ymm6, ymm10 vpxord ymm7, ymm7, ymm11 vprord ymm4, ymm4, 12 vprord ymm5, ymm5, 12 vprord ymm6, ymm6, 12 vprord ymm7, ymm7, 12 vpaddd ymm0, ymm0, ymm17 vpaddd ymm1, ymm1, ymm19 vpaddd ymm2, ymm2, ymm21 vpaddd ymm3, ymm3, ymm23 vpaddd ymm0, ymm0, ymm4 vpaddd ymm1, ymm1, ymm5 vpaddd ymm2, ymm2, ymm6 vpaddd ymm3, ymm3, ymm7 vpxord ymm12, ymm12, ymm0 vpxord ymm13, ymm13, ymm1 vpxord ymm14, ymm14, ymm2 vpxord ymm15, ymm15, ymm3 vprord ymm12, ymm12, 8 vprord ymm13, ymm13, 8 vprord ymm14, ymm14, 8 vprord ymm15, ymm15, 8 vpaddd ymm8, ymm8, ymm12 vpaddd ymm9, ymm9, ymm13 vpaddd ymm10, ymm10, ymm14 vpaddd ymm11, ymm11, ymm15 vpxord ymm4, ymm4, ymm8 vpxord ymm5, ymm5, ymm9 vpxord ymm6, ymm6, ymm10 vpxord ymm7, ymm7, ymm11 vprord ymm4, ymm4, 7 vprord ymm5, ymm5, 7 vprord ymm6, ymm6, 7 vprord ymm7, ymm7, 7 vpaddd ymm0, ymm0, ymm24 vpaddd ymm1, ymm1, ymm26 vpaddd ymm2, ymm2, ymm28 vpaddd ymm3, ymm3, ymm30 vpaddd ymm0, ymm0, ymm5 vpaddd ymm1, ymm1, ymm6 vpaddd ymm2, ymm2, ymm7 vpaddd ymm3, ymm3, ymm4 vpxord ymm15, ymm15, ymm0 vpxord ymm12, ymm12, ymm1 vpxord ymm13, ymm13, ymm2 vpxord ymm14, ymm14, ymm3 vprord ymm15, ymm15, 16 vprord ymm12, ymm12, 16 vprord ymm13, ymm13, 16 vprord ymm14, ymm14, 16 vpaddd ymm10, ymm10, ymm15 vpaddd ymm11, ymm11, ymm12 vpaddd ymm8, ymm8, ymm13 vpaddd ymm9, ymm9, ymm14 vpxord ymm5, ymm5, ymm10 vpxord ymm6, ymm6, ymm11 vpxord ymm7, ymm7, ymm8 vpxord ymm4, ymm4, ymm9 vprord ymm5, ymm5, 12 vprord ymm6, ymm6, 12 vprord ymm7, ymm7, 12 vprord ymm4, ymm4, 12 vpaddd ymm0, ymm0, ymm25 vpaddd ymm1, ymm1, ymm27 vpaddd ymm2, ymm2, ymm29 vpaddd ymm3, ymm3, ymm31 vpaddd ymm0, ymm0, ymm5 vpaddd ymm1, ymm1, ymm6 vpaddd ymm2, ymm2, ymm7 vpaddd ymm3, ymm3, ymm4 vpxord ymm15, ymm15, ymm0 vpxord ymm12, ymm12, ymm1 vpxord ymm13, ymm13, ymm2 vpxord ymm14, ymm14, ymm3 vprord ymm15, ymm15, 8 vprord ymm12, ymm12, 8 vprord ymm13, ymm13, 8 vprord ymm14, ymm14, 8 vpaddd ymm10, ymm10, ymm15 vpaddd ymm11, ymm11, ymm12 vpaddd ymm8, ymm8, ymm13 vpaddd ymm9, ymm9, ymm14 vpxord ymm5, ymm5, ymm10 vpxord ymm6, ymm6, ymm11 vpxord ymm7, ymm7, ymm8 vpxord ymm4, ymm4, ymm9 vprord ymm5, ymm5, 7 vprord ymm6, ymm6, 7 vprord ymm7, ymm7, 7 vprord ymm4, ymm4, 7 vpaddd ymm0, ymm0, ymm18 vpaddd ymm1, ymm1, ymm19 vpaddd ymm2, ymm2, ymm23 vpaddd ymm3, ymm3, ymm20 vpaddd ymm0, ymm0, ymm4 vpaddd ymm1, ymm1, ymm5 vpaddd ymm2, ymm2, ymm6 vpaddd ymm3, ymm3, ymm7 vpxord ymm12, ymm12, ymm0 vpxord ymm13, ymm13, ymm1 vpxord ymm14, ymm14, ymm2 vpxord ymm15, ymm15, ymm3 vprord ymm12, ymm12, 16 vprord ymm13, ymm13, 16 vprord ymm14, ymm14, 16 vprord ymm15, ymm15, 16 vpaddd ymm8, ymm8, ymm12 vpaddd ymm9, ymm9, ymm13 vpaddd ymm10, ymm10, ymm14 vpaddd ymm11, ymm11, ymm15 vpxord ymm4, ymm4, ymm8 vpxord ymm5, ymm5, ymm9 vpxord ymm6, ymm6, ymm10 vpxord ymm7, ymm7, ymm11 vprord ymm4, ymm4, 12 vprord ymm5, ymm5, 12 vprord ymm6, ymm6, 12 vprord ymm7, ymm7, 12 vpaddd ymm0, ymm0, ymm22 vpaddd ymm1, ymm1, ymm26 vpaddd ymm2, ymm2, ymm16 vpaddd ymm3, ymm3, ymm29 vpaddd ymm0, ymm0, ymm4 vpaddd ymm1, ymm1, ymm5 vpaddd ymm2, ymm2, ymm6 vpaddd ymm3, ymm3, ymm7 vpxord ymm12, ymm12, ymm0 vpxord ymm13, ymm13, ymm1 vpxord ymm14, ymm14, ymm2 vpxord ymm15, ymm15, ymm3 vprord ymm12, ymm12, 8 vprord ymm13, ymm13, 8 vprord ymm14, ymm14, 8 vprord ymm15, ymm15, 8 vpaddd ymm8, ymm8, ymm12 vpaddd ymm9, ymm9, ymm13 vpaddd ymm10, ymm10, ymm14 vpaddd ymm11, ymm11, ymm15 vpxord ymm4, ymm4, ymm8 vpxord ymm5, ymm5, ymm9 vpxord ymm6, ymm6, ymm10 vpxord ymm7, ymm7, ymm11 vprord ymm4, ymm4, 7 vprord ymm5, ymm5, 7 vprord ymm6, ymm6, 7 vprord ymm7, ymm7, 7 vpaddd ymm0, ymm0, ymm17 vpaddd ymm1, ymm1, ymm28 vpaddd ymm2, ymm2, ymm25 vpaddd ymm3, ymm3, ymm31 vpaddd ymm0, ymm0, ymm5 vpaddd ymm1, ymm1, ymm6 vpaddd ymm2, ymm2, ymm7 vpaddd ymm3, ymm3, ymm4 vpxord ymm15, ymm15, ymm0 vpxord ymm12, ymm12, ymm1 vpxord ymm13, ymm13, ymm2 vpxord ymm14, ymm14, ymm3 vprord ymm15, ymm15, 16 vprord ymm12, ymm12, 16 vprord ymm13, ymm13, 16 vprord ymm14, ymm14, 16 vpaddd ymm10, ymm10, ymm15 vpaddd ymm11, ymm11, ymm12 vpaddd ymm8, ymm8, ymm13 vpaddd ymm9, ymm9, ymm14 vpxord ymm5, ymm5, ymm10 vpxord ymm6, ymm6, ymm11 vpxord ymm7, ymm7, ymm8 vpxord ymm4, ymm4, ymm9 vprord ymm5, ymm5, 12 vprord ymm6, ymm6, 12 vprord ymm7, ymm7, 12 vprord ymm4, ymm4, 12 vpaddd ymm0, ymm0, ymm27 vpaddd ymm1, ymm1, ymm21 vpaddd ymm2, ymm2, ymm30 vpaddd ymm3, ymm3, ymm24 vpaddd ymm0, ymm0, ymm5 vpaddd ymm1, ymm1, ymm6 vpaddd ymm2, ymm2, ymm7 vpaddd ymm3, ymm3, ymm4 vpxord ymm15, ymm15, ymm0 vpxord ymm12, ymm12, ymm1 vpxord ymm13, ymm13, ymm2 vpxord ymm14, ymm14, ymm3 vprord ymm15, ymm15, 8 vprord ymm12, ymm12, 8 vprord ymm13, ymm13, 8 vprord ymm14, ymm14, 8 vpaddd ymm10, ymm10, ymm15 vpaddd ymm11, ymm11, ymm12 vpaddd ymm8, ymm8, ymm13 vpaddd ymm9, ymm9, ymm14 vpxord ymm5, ymm5, ymm10 vpxord ymm6, ymm6, ymm11 vpxord ymm7, ymm7, ymm8 vpxord ymm4, ymm4, ymm9 vprord ymm5, ymm5, 7 vprord ymm6, ymm6, 7 vprord ymm7, ymm7, 7 vprord ymm4, ymm4, 7 vpaddd ymm0, ymm0, ymm19 vpaddd ymm1, ymm1, ymm26 vpaddd ymm2, ymm2, ymm29 vpaddd ymm3, ymm3, ymm23 vpaddd ymm0, ymm0, ymm4 vpaddd ymm1, ymm1, ymm5 vpaddd ymm2, ymm2, ymm6 vpaddd ymm3, ymm3, ymm7 vpxord ymm12, ymm12, ymm0 vpxord ymm13, ymm13, ymm1 vpxord ymm14, ymm14, ymm2 vpxord ymm15, ymm15, ymm3 vprord ymm12, ymm12, 16 vprord ymm13, ymm13, 16 vprord ymm14, ymm14, 16 vprord ymm15, ymm15, 16 vpaddd ymm8, ymm8, ymm12 vpaddd ymm9, ymm9, ymm13 vpaddd ymm10, ymm10, ymm14 vpaddd ymm11, ymm11, ymm15 vpxord ymm4, ymm4, ymm8 vpxord ymm5, ymm5, ymm9 vpxord ymm6, ymm6, ymm10 vpxord ymm7, ymm7, ymm11 vprord ymm4, ymm4, 12 vprord ymm5, ymm5, 12 vprord ymm6, ymm6, 12 vprord ymm7, ymm7, 12 vpaddd ymm0, ymm0, ymm20 vpaddd ymm1, ymm1, ymm28 vpaddd ymm2, ymm2, ymm18 vpaddd ymm3, ymm3, ymm30 vpaddd ymm0, ymm0, ymm4 vpaddd ymm1, ymm1, ymm5 vpaddd ymm2, ymm2, ymm6 vpaddd ymm3, ymm3, ymm7 vpxord ymm12, ymm12, ymm0 vpxord ymm13, ymm13, ymm1 vpxord ymm14, ymm14, ymm2 vpxord ymm15, ymm15, ymm3 vprord ymm12, ymm12, 8 vprord ymm13, ymm13, 8 vprord ymm14, ymm14, 8 vprord ymm15, ymm15, 8 vpaddd ymm8, ymm8, ymm12 vpaddd ymm9, ymm9, ymm13 vpaddd ymm10, ymm10, ymm14 vpaddd ymm11, ymm11, ymm15 vpxord ymm4, ymm4, ymm8 vpxord ymm5, ymm5, ymm9 vpxord ymm6, ymm6, ymm10 vpxord ymm7, ymm7, ymm11 vprord ymm4, ymm4, 7 vprord ymm5, ymm5, 7 vprord ymm6, ymm6, 7 vprord ymm7, ymm7, 7 vpaddd ymm0, ymm0, ymm22 vpaddd ymm1, ymm1, ymm25 vpaddd ymm2, ymm2, ymm27 vpaddd ymm3, ymm3, ymm24 vpaddd ymm0, ymm0, ymm5 vpaddd ymm1, ymm1, ymm6 vpaddd ymm2, ymm2, ymm7 vpaddd ymm3, ymm3, ymm4 vpxord ymm15, ymm15, ymm0 vpxord ymm12, ymm12, ymm1 vpxord ymm13, ymm13, ymm2 vpxord ymm14, ymm14, ymm3 vprord ymm15, ymm15, 16 vprord ymm12, ymm12, 16 vprord ymm13, ymm13, 16 vprord ymm14, ymm14, 16 vpaddd ymm10, ymm10, ymm15 vpaddd ymm11, ymm11, ymm12 vpaddd ymm8, ymm8, ymm13 vpaddd ymm9, ymm9, ymm14 vpxord ymm5, ymm5, ymm10 vpxord ymm6, ymm6, ymm11 vpxord ymm7, ymm7, ymm8 vpxord ymm4, ymm4, ymm9 vprord ymm5, ymm5, 12 vprord ymm6, ymm6, 12 vprord ymm7, ymm7, 12 vprord ymm4, ymm4, 12 vpaddd ymm0, ymm0, ymm21 vpaddd ymm1, ymm1, ymm16 vpaddd ymm2, ymm2, ymm31 vpaddd ymm3, ymm3, ymm17 vpaddd ymm0, ymm0, ymm5 vpaddd ymm1, ymm1, ymm6 vpaddd ymm2, ymm2, ymm7 vpaddd ymm3, ymm3, ymm4 vpxord ymm15, ymm15, ymm0 vpxord ymm12, ymm12, ymm1 vpxord ymm13, ymm13, ymm2 vpxord ymm14, ymm14, ymm3 vprord ymm15, ymm15, 8 vprord ymm12, ymm12, 8 vprord ymm13, ymm13, 8 vprord ymm14, ymm14, 8 vpaddd ymm10, ymm10, ymm15 vpaddd ymm11, ymm11, ymm12 vpaddd ymm8, ymm8, ymm13 vpaddd ymm9, ymm9, ymm14 vpxord ymm5, ymm5, ymm10 vpxord ymm6, ymm6, ymm11 vpxord ymm7, ymm7, ymm8 vpxord ymm4, ymm4, ymm9 vprord ymm5, ymm5, 7 vprord ymm6, ymm6, 7 vprord ymm7, ymm7, 7 vprord ymm4, ymm4, 7 vpaddd ymm0, ymm0, ymm26 vpaddd ymm1, ymm1, ymm28 vpaddd ymm2, ymm2, ymm30 vpaddd ymm3, ymm3, ymm29 vpaddd ymm0, ymm0, ymm4 vpaddd ymm1, ymm1, ymm5 vpaddd ymm2, ymm2, ymm6 vpaddd ymm3, ymm3, ymm7 vpxord ymm12, ymm12, ymm0 vpxord ymm13, ymm13, ymm1 vpxord ymm14, ymm14, ymm2 vpxord ymm15, ymm15, ymm3 vprord ymm12, ymm12, 16 vprord ymm13, ymm13, 16 vprord ymm14, ymm14, 16 vprord ymm15, ymm15, 16 vpaddd ymm8, ymm8, ymm12 vpaddd ymm9, ymm9, ymm13 vpaddd ymm10, ymm10, ymm14 vpaddd ymm11, ymm11, ymm15 vpxord ymm4, ymm4, ymm8 vpxord ymm5, ymm5, ymm9 vpxord ymm6, ymm6, ymm10 vpxord ymm7, ymm7, ymm11 vprord ymm4, ymm4, 12 vprord ymm5, ymm5, 12 vprord ymm6, ymm6, 12 vprord ymm7, ymm7, 12 vpaddd ymm0, ymm0, ymm23 vpaddd ymm1, ymm1, ymm25 vpaddd ymm2, ymm2, ymm19 vpaddd ymm3, ymm3, ymm31 vpaddd ymm0, ymm0, ymm4 vpaddd ymm1, ymm1, ymm5 vpaddd ymm2, ymm2, ymm6 vpaddd ymm3, ymm3, ymm7 vpxord ymm12, ymm12, ymm0 vpxord ymm13, ymm13, ymm1 vpxord ymm14, ymm14, ymm2 vpxord ymm15, ymm15, ymm3 vprord ymm12, ymm12, 8 vprord ymm13, ymm13, 8 vprord ymm14, ymm14, 8 vprord ymm15, ymm15, 8 vpaddd ymm8, ymm8, ymm12 vpaddd ymm9, ymm9, ymm13 vpaddd ymm10, ymm10, ymm14 vpaddd ymm11, ymm11, ymm15 vpxord ymm4, ymm4, ymm8 vpxord ymm5, ymm5, ymm9 vpxord ymm6, ymm6, ymm10 vpxord ymm7, ymm7, ymm11 vprord ymm4, ymm4, 7 vprord ymm5, ymm5, 7 vprord ymm6, ymm6, 7 vprord ymm7, ymm7, 7 vpaddd ymm0, ymm0, ymm20 vpaddd ymm1, ymm1, ymm27 vpaddd ymm2, ymm2, ymm21 vpaddd ymm3, ymm3, ymm17 vpaddd ymm0, ymm0, ymm5 vpaddd ymm1, ymm1, ymm6 vpaddd ymm2, ymm2, ymm7 vpaddd ymm3, ymm3, ymm4 vpxord ymm15, ymm15, ymm0 vpxord ymm12, ymm12, ymm1 vpxord ymm13, ymm13, ymm2 vpxord ymm14, ymm14, ymm3 vprord ymm15, ymm15, 16 vprord ymm12, ymm12, 16 vprord ymm13, ymm13, 16 vprord ymm14, ymm14, 16 vpaddd ymm10, ymm10, ymm15 vpaddd ymm11, ymm11, ymm12 vpaddd ymm8, ymm8, ymm13 vpaddd ymm9, ymm9, ymm14 vpxord ymm5, ymm5, ymm10 vpxord ymm6, ymm6, ymm11 vpxord ymm7, ymm7, ymm8 vpxord ymm4, ymm4, ymm9 vprord ymm5, ymm5, 12 vprord ymm6, ymm6, 12 vprord ymm7, ymm7, 12 vprord ymm4, ymm4, 12 vpaddd ymm0, ymm0, ymm16 vpaddd ymm1, ymm1, ymm18 vpaddd ymm2, ymm2, ymm24 vpaddd ymm3, ymm3, ymm22 vpaddd ymm0, ymm0, ymm5 vpaddd ymm1, ymm1, ymm6 vpaddd ymm2, ymm2, ymm7 vpaddd ymm3, ymm3, ymm4 vpxord ymm15, ymm15, ymm0 vpxord ymm12, ymm12, ymm1 vpxord ymm13, ymm13, ymm2 vpxord ymm14, ymm14, ymm3 vprord ymm15, ymm15, 8 vprord ymm12, ymm12, 8 vprord ymm13, ymm13, 8 vprord ymm14, ymm14, 8 vpaddd ymm10, ymm10, ymm15 vpaddd ymm11, ymm11, ymm12 vpaddd ymm8, ymm8, ymm13 vpaddd ymm9, ymm9, ymm14 vpxord ymm5, ymm5, ymm10 vpxord ymm6, ymm6, ymm11 vpxord ymm7, ymm7, ymm8 vpxord ymm4, ymm4, ymm9 vprord ymm5, ymm5, 7 vprord ymm6, ymm6, 7 vprord ymm7, ymm7, 7 vprord ymm4, ymm4, 7 vpaddd ymm0, ymm0, ymm28 vpaddd ymm1, ymm1, ymm25 vpaddd ymm2, ymm2, ymm31 vpaddd ymm3, ymm3, ymm30 vpaddd ymm0, ymm0, ymm4 vpaddd ymm1, ymm1, ymm5 vpaddd ymm2, ymm2, ymm6 vpaddd ymm3, ymm3, ymm7 vpxord ymm12, ymm12, ymm0 vpxord ymm13, ymm13, ymm1 vpxord ymm14, ymm14, ymm2 vpxord ymm15, ymm15, ymm3 vprord ymm12, ymm12, 16 vprord ymm13, ymm13, 16 vprord ymm14, ymm14, 16 vprord ymm15, ymm15, 16 vpaddd ymm8, ymm8, ymm12 vpaddd ymm9, ymm9, ymm13 vpaddd ymm10, ymm10, ymm14 vpaddd ymm11, ymm11, ymm15 vpxord ymm4, ymm4, ymm8 vpxord ymm5, ymm5, ymm9 vpxord ymm6, ymm6, ymm10 vpxord ymm7, ymm7, ymm11 vprord ymm4, ymm4, 12 vprord ymm5, ymm5, 12 vprord ymm6, ymm6, 12 vprord ymm7, ymm7, 12 vpaddd ymm0, ymm0, ymm29 vpaddd ymm1, ymm1, ymm27 vpaddd ymm2, ymm2, ymm26 vpaddd ymm3, ymm3, ymm24 vpaddd ymm0, ymm0, ymm4 vpaddd ymm1, ymm1, ymm5 vpaddd ymm2, ymm2, ymm6 vpaddd ymm3, ymm3, ymm7 vpxord ymm12, ymm12, ymm0 vpxord ymm13, ymm13, ymm1 vpxord ymm14, ymm14, ymm2 vpxord ymm15, ymm15, ymm3 vprord ymm12, ymm12, 8 vprord ymm13, ymm13, 8 vprord ymm14, ymm14, 8 vprord ymm15, ymm15, 8 vpaddd ymm8, ymm8, ymm12 vpaddd ymm9, ymm9, ymm13 vpaddd ymm10, ymm10, ymm14 vpaddd ymm11, ymm11, ymm15 vpxord ymm4, ymm4, ymm8 vpxord ymm5, ymm5, ymm9 vpxord ymm6, ymm6, ymm10 vpxord ymm7, ymm7, ymm11 vprord ymm4, ymm4, 7 vprord ymm5, ymm5, 7 vprord ymm6, ymm6, 7 vprord ymm7, ymm7, 7 vpaddd ymm0, ymm0, ymm23 vpaddd ymm1, ymm1, ymm21 vpaddd ymm2, ymm2, ymm16 vpaddd ymm3, ymm3, ymm22 vpaddd ymm0, ymm0, ymm5 vpaddd ymm1, ymm1, ymm6 vpaddd ymm2, ymm2, ymm7 vpaddd ymm3, ymm3, ymm4 vpxord ymm15, ymm15, ymm0 vpxord ymm12, ymm12, ymm1 vpxord ymm13, ymm13, ymm2 vpxord ymm14, ymm14, ymm3 vprord ymm15, ymm15, 16 vprord ymm12, ymm12, 16 vprord ymm13, ymm13, 16 vprord ymm14, ymm14, 16 vpaddd ymm10, ymm10, ymm15 vpaddd ymm11, ymm11, ymm12 vpaddd ymm8, ymm8, ymm13 vpaddd ymm9, ymm9, ymm14 vpxord ymm5, ymm5, ymm10 vpxord ymm6, ymm6, ymm11 vpxord ymm7, ymm7, ymm8 vpxord ymm4, ymm4, ymm9 vprord ymm5, ymm5, 12 vprord ymm6, ymm6, 12 vprord ymm7, ymm7, 12 vprord ymm4, ymm4, 12 vpaddd ymm0, ymm0, ymm18 vpaddd ymm1, ymm1, ymm19 vpaddd ymm2, ymm2, ymm17 vpaddd ymm3, ymm3, ymm20 vpaddd ymm0, ymm0, ymm5 vpaddd ymm1, ymm1, ymm6 vpaddd ymm2, ymm2, ymm7 vpaddd ymm3, ymm3, ymm4 vpxord ymm15, ymm15, ymm0 vpxord ymm12, ymm12, ymm1 vpxord ymm13, ymm13, ymm2 vpxord ymm14, ymm14, ymm3 vprord ymm15, ymm15, 8 vprord ymm12, ymm12, 8 vprord ymm13, ymm13, 8 vprord ymm14, ymm14, 8 vpaddd ymm10, ymm10, ymm15 vpaddd ymm11, ymm11, ymm12 vpaddd ymm8, ymm8, ymm13 vpaddd ymm9, ymm9, ymm14 vpxord ymm5, ymm5, ymm10 vpxord ymm6, ymm6, ymm11 vpxord ymm7, ymm7, ymm8 vpxord ymm4, ymm4, ymm9 vprord ymm5, ymm5, 7 vprord ymm6, ymm6, 7 vprord ymm7, ymm7, 7 vprord ymm4, ymm4, 7 vpaddd ymm0, ymm0, ymm25 vpaddd ymm1, ymm1, ymm27 vpaddd ymm2, ymm2, ymm24 vpaddd ymm3, ymm3, ymm31 vpaddd ymm0, ymm0, ymm4 vpaddd ymm1, ymm1, ymm5 vpaddd ymm2, ymm2, ymm6 vpaddd ymm3, ymm3, ymm7 vpxord ymm12, ymm12, ymm0 vpxord ymm13, ymm13, ymm1 vpxord ymm14, ymm14, ymm2 vpxord ymm15, ymm15, ymm3 vprord ymm12, ymm12, 16 vprord ymm13, ymm13, 16 vprord ymm14, ymm14, 16 vprord ymm15, ymm15, 16 vpaddd ymm8, ymm8, ymm12 vpaddd ymm9, ymm9, ymm13 vpaddd ymm10, ymm10, ymm14 vpaddd ymm11, ymm11, ymm15 vpxord ymm4, ymm4, ymm8 vpxord ymm5, ymm5, ymm9 vpxord ymm6, ymm6, ymm10 vpxord ymm7, ymm7, ymm11 vprord ymm4, ymm4, 12 vprord ymm5, ymm5, 12 vprord ymm6, ymm6, 12 vprord ymm7, ymm7, 12 vpaddd ymm0, ymm0, ymm30 vpaddd ymm1, ymm1, ymm21 vpaddd ymm2, ymm2, ymm28 vpaddd ymm3, ymm3, ymm17 vpaddd ymm0, ymm0, ymm4 vpaddd ymm1, ymm1, ymm5 vpaddd ymm2, ymm2, ymm6 vpaddd ymm3, ymm3, ymm7 vpxord ymm12, ymm12, ymm0 vpxord ymm13, ymm13, ymm1 vpxord ymm14, ymm14, ymm2 vpxord ymm15, ymm15, ymm3 vprord ymm12, ymm12, 8 vprord ymm13, ymm13, 8 vprord ymm14, ymm14, 8 vprord ymm15, ymm15, 8 vpaddd ymm8, ymm8, ymm12 vpaddd ymm9, ymm9, ymm13 vpaddd ymm10, ymm10, ymm14 vpaddd ymm11, ymm11, ymm15 vpxord ymm4, ymm4, ymm8 vpxord ymm5, ymm5, ymm9 vpxord ymm6, ymm6, ymm10 vpxord ymm7, ymm7, ymm11 vprord ymm4, ymm4, 7 vprord ymm5, ymm5, 7 vprord ymm6, ymm6, 7 vprord ymm7, ymm7, 7 vpaddd ymm0, ymm0, ymm29 vpaddd ymm1, ymm1, ymm16 vpaddd ymm2, ymm2, ymm18 vpaddd ymm3, ymm3, ymm20 vpaddd ymm0, ymm0, ymm5 vpaddd ymm1, ymm1, ymm6 vpaddd ymm2, ymm2, ymm7 vpaddd ymm3, ymm3, ymm4 vpxord ymm15, ymm15, ymm0 vpxord ymm12, ymm12, ymm1 vpxord ymm13, ymm13, ymm2 vpxord ymm14, ymm14, ymm3 vprord ymm15, ymm15, 16 vprord ymm12, ymm12, 16 vprord ymm13, ymm13, 16 vprord ymm14, ymm14, 16 vpaddd ymm10, ymm10, ymm15 vpaddd ymm11, ymm11, ymm12 vpaddd ymm8, ymm8, ymm13 vpaddd ymm9, ymm9, ymm14 vpxord ymm5, ymm5, ymm10 vpxord ymm6, ymm6, ymm11 vpxord ymm7, ymm7, ymm8 vpxord ymm4, ymm4, ymm9 vprord ymm5, ymm5, 12 vprord ymm6, ymm6, 12 vprord ymm7, ymm7, 12 vprord ymm4, ymm4, 12 vpaddd ymm0, ymm0, ymm19 vpaddd ymm1, ymm1, ymm26 vpaddd ymm2, ymm2, ymm22 vpaddd ymm3, ymm3, ymm23 vpaddd ymm0, ymm0, ymm5 vpaddd ymm1, ymm1, ymm6 vpaddd ymm2, ymm2, ymm7 vpaddd ymm3, ymm3, ymm4 vpxord ymm15, ymm15, ymm0 vpxord ymm12, ymm12, ymm1 vpxord ymm13, ymm13, ymm2 vpxord ymm14, ymm14, ymm3 vprord ymm15, ymm15, 8 vprord ymm12, ymm12, 8 vprord ymm13, ymm13, 8 vprord ymm14, ymm14, 8 vpaddd ymm10, ymm10, ymm15 vpaddd ymm11, ymm11, ymm12 vpaddd ymm8, ymm8, ymm13 vpaddd ymm9, ymm9, ymm14 vpxord ymm5, ymm5, ymm10 vpxord ymm6, ymm6, ymm11 vpxord ymm7, ymm7, ymm8 vpxord ymm4, ymm4, ymm9 vprord ymm5, ymm5, 7 vprord ymm6, ymm6, 7 vprord ymm7, ymm7, 7 vprord ymm4, ymm4, 7 vpaddd ymm0, ymm0, ymm27 vpaddd ymm1, ymm1, ymm21 vpaddd ymm2, ymm2, ymm17 vpaddd ymm3, ymm3, ymm24 vpaddd ymm0, ymm0, ymm4 vpaddd ymm1, ymm1, ymm5 vpaddd ymm2, ymm2, ymm6 vpaddd ymm3, ymm3, ymm7 vpxord ymm12, ymm12, ymm0 vpxord ymm13, ymm13, ymm1 vpxord ymm14, ymm14, ymm2 vpxord ymm15, ymm15, ymm3 vprord ymm12, ymm12, 16 vprord ymm13, ymm13, 16 vprord ymm14, ymm14, 16 vprord ymm15, ymm15, 16 vpaddd ymm8, ymm8, ymm12 vpaddd ymm9, ymm9, ymm13 vpaddd ymm10, ymm10, ymm14 vpaddd ymm11, ymm11, ymm15 vpxord ymm4, ymm4, ymm8 vpxord ymm5, ymm5, ymm9 vpxord ymm6, ymm6, ymm10 vpxord ymm7, ymm7, ymm11 vprord ymm4, ymm4, 12 vprord ymm5, ymm5, 12 vprord ymm6, ymm6, 12 vprord ymm7, ymm7, 12 vpaddd ymm0, ymm0, ymm31 vpaddd ymm1, ymm1, ymm16 vpaddd ymm2, ymm2, ymm25 vpaddd ymm3, ymm3, ymm22 vpaddd ymm0, ymm0, ymm4 vpaddd ymm1, ymm1, ymm5 vpaddd ymm2, ymm2, ymm6 vpaddd ymm3, ymm3, ymm7 vpxord ymm12, ymm12, ymm0 vpxord ymm13, ymm13, ymm1 vpxord ymm14, ymm14, ymm2 vpxord ymm15, ymm15, ymm3 vprord ymm12, ymm12, 8 vprord ymm13, ymm13, 8 vprord ymm14, ymm14, 8 vprord ymm15, ymm15, 8 vpaddd ymm8, ymm8, ymm12 vpaddd ymm9, ymm9, ymm13 vpaddd ymm10, ymm10, ymm14 vpaddd ymm11, ymm11, ymm15 vpxord ymm4, ymm4, ymm8 vpxord ymm5, ymm5, ymm9 vpxord ymm6, ymm6, ymm10 vpxord ymm7, ymm7, ymm11 vprord ymm4, ymm4, 7 vprord ymm5, ymm5, 7 vprord ymm6, ymm6, 7 vprord ymm7, ymm7, 7 vpaddd ymm0, ymm0, ymm30 vpaddd ymm1, ymm1, ymm18 vpaddd ymm2, ymm2, ymm19 vpaddd ymm3, ymm3, ymm23 vpaddd ymm0, ymm0, ymm5 vpaddd ymm1, ymm1, ymm6 vpaddd ymm2, ymm2, ymm7 vpaddd ymm3, ymm3, ymm4 vpxord ymm15, ymm15, ymm0 vpxord ymm12, ymm12, ymm1 vpxord ymm13, ymm13, ymm2 vpxord ymm14, ymm14, ymm3 vprord ymm15, ymm15, 16 vprord ymm12, ymm12, 16 vprord ymm13, ymm13, 16 vprord ymm14, ymm14, 16 vpaddd ymm10, ymm10, ymm15 vpaddd ymm11, ymm11, ymm12 vpaddd ymm8, ymm8, ymm13 vpaddd ymm9, ymm9, ymm14 vpxord ymm5, ymm5, ymm10 vpxord ymm6, ymm6, ymm11 vpxord ymm7, ymm7, ymm8 vpxord ymm4, ymm4, ymm9 vprord ymm5, ymm5, 12 vprord ymm6, ymm6, 12 vprord ymm7, ymm7, 12 vprord ymm4, ymm4, 12 vpaddd ymm0, ymm0, ymm26 vpaddd ymm1, ymm1, ymm28 vpaddd ymm2, ymm2, ymm20 vpaddd ymm3, ymm3, ymm29 vpaddd ymm0, ymm0, ymm5 vpaddd ymm1, ymm1, ymm6 vpaddd ymm2, ymm2, ymm7 vpaddd ymm3, ymm3, ymm4 vpxord ymm15, ymm15, ymm0 vpxord ymm12, ymm12, ymm1 vpxord ymm13, ymm13, ymm2 vpxord ymm14, ymm14, ymm3 vprord ymm15, ymm15, 8 vprord ymm12, ymm12, 8 vprord ymm13, ymm13, 8 vprord ymm14, ymm14, 8 vpaddd ymm10, ymm10, ymm15 vpaddd ymm11, ymm11, ymm12 vpaddd ymm8, ymm8, ymm13 vpaddd ymm9, ymm9, ymm14 vpxord ymm5, ymm5, ymm10 vpxord ymm6, ymm6, ymm11 vpxord ymm7, ymm7, ymm8 vpxord ymm4, ymm4, ymm9 vprord ymm5, ymm5, 7 vprord ymm6, ymm6, 7 vprord ymm7, ymm7, 7 vprord ymm4, ymm4, 7 vpxor ymm0, ymm0, ymm8 vpxor ymm1, ymm1, ymm9 vpxor ymm2, ymm2, ymm10 vpxor ymm3, ymm3, ymm11 vpxor ymm4, ymm4, ymm12 vpxor ymm5, ymm5, ymm13 vpxor ymm6, ymm6, ymm14 vpxor ymm7, ymm7, ymm15 movzx eax, byte ptr [rbp+78H] jne innerloop8 mov rbx, qword ptr [rbp+90H] vunpcklps ymm8, ymm0, ymm1 vunpcklps ymm9, ymm2, ymm3 vunpckhps ymm10, ymm0, ymm1 vunpcklps ymm11, ymm4, ymm5 vunpcklps ymm0, ymm6, ymm7 vshufps ymm12, ymm8, ymm9, 78 vblendps ymm1, ymm8, ymm12, 0CCH vshufps ymm8, ymm11, ymm0, 78 vunpckhps ymm13, ymm2, ymm3 vblendps ymm2, ymm11, ymm8, 0CCH vblendps ymm3, ymm12, ymm9, 0CCH vperm2f128 ymm12, ymm1, ymm2, 20H vmovups ymmword ptr [rbx], ymm12 vunpckhps ymm14, ymm4, ymm5 vblendps ymm4, ymm8, ymm0, 0CCH vunpckhps ymm15, ymm6, ymm7 vperm2f128 ymm7, ymm3, ymm4, 20H vmovups ymmword ptr [rbx+20H], ymm7 vshufps ymm5, ymm10, ymm13, 78 vblendps ymm6, ymm5, ymm13, 0CCH vshufps ymm13, ymm14, ymm15, 78 vblendps ymm10, ymm10, ymm5, 0CCH vblendps ymm14, ymm14, ymm13, 0CCH vperm2f128 ymm8, ymm10, ymm14, 20H vmovups ymmword ptr [rbx+40H], ymm8 vblendps ymm15, ymm13, ymm15, 0CCH vperm2f128 ymm13, ymm6, ymm15, 20H vmovups ymmword ptr [rbx+60H], ymm13 vperm2f128 ymm9, ymm1, ymm2, 31H vperm2f128 ymm11, ymm3, ymm4, 31H vmovups ymmword ptr [rbx+80H], ymm9 vperm2f128 ymm14, ymm10, ymm14, 31H vperm2f128 ymm15, ymm6, ymm15, 31H vmovups ymmword ptr [rbx+0A0H], ymm11 vmovups ymmword ptr [rbx+0C0H], ymm14 vmovups ymmword ptr [rbx+0E0H], ymm15 vmovdqa ymm0, ymmword ptr [rsp] vmovdqa ymm2, ymmword ptr [rsp+40H] vmovdqa32 ymm0 {k1}, ymmword ptr [rsp+1H*20H] vmovdqa32 ymm2 {k1}, ymmword ptr [rsp+3H*20H] vmovdqa ymmword ptr [rsp], ymm0 vmovdqa ymmword ptr [rsp+40H], ymm2 add rbx, 256 mov qword ptr [rbp+90H], rbx add rdi, 64 sub rsi, 8 final7blocks: mov rbx, qword ptr [rbp+90H] mov r15, qword ptr [rsp+80H] movzx r13, byte ptr [rbp+78H] movzx r12, byte ptr [rbp+88H] test esi, 4H je final3blocks vbroadcasti32x4 zmm0, xmmword ptr [rcx] vbroadcasti32x4 zmm1, xmmword ptr [rcx+1H*10H] vmovdqa xmm12, xmmword ptr [rsp] vmovdqa xmm13, xmmword ptr [rsp+40H] vpunpckldq xmm14, xmm12, xmm13 vpunpckhdq xmm15, xmm12, xmm13 vpermq ymm14, ymm14, 0DCH vpermq ymm15, ymm15, 0DCH vpbroadcastd zmm12, dword ptr [BLAKE3_BLOCK_LEN] vinserti64x4 zmm13, zmm14, ymm15, 01H mov eax, 17476 kmovw k2, eax vpblendmd zmm13 {k2}, zmm13, zmm12 vbroadcasti32x4 zmm15, xmmword ptr [BLAKE3_IV] mov r8, qword ptr [rdi] mov r9, qword ptr [rdi+8H] mov r10, qword ptr [rdi+10H] mov r11, qword ptr [rdi+18H] mov eax, 43690 kmovw k3, eax mov eax, 34952 kmovw k4, eax movzx eax, byte ptr [rbp+80H] or eax, r13d xor edx, edx ALIGN 16 innerloop4: mov r14d, eax or eax, r12d add rdx, 64 cmp rdx, r15 cmovne eax, r14d mov dword ptr [rsp+88H], eax vmovdqa32 zmm2, zmm15 vpbroadcastd zmm8, dword ptr [rsp+22H*4H] vpblendmd zmm3 {k4}, zmm13, zmm8 vmovups zmm8, zmmword ptr [r8+rdx-1H*40H] vinserti32x4 zmm8, zmm8, xmmword ptr [r9+rdx-4H*10H], 01H vinserti32x4 zmm8, zmm8, xmmword ptr [r10+rdx-4H*10H], 02H vinserti32x4 zmm8, zmm8, xmmword ptr [r11+rdx-4H*10H], 03H vmovups zmm9, zmmword ptr [r8+rdx-30H] vinserti32x4 zmm9, zmm9, xmmword ptr [r9+rdx-3H*10H], 01H vinserti32x4 zmm9, zmm9, xmmword ptr [r10+rdx-3H*10H], 02H vinserti32x4 zmm9, zmm9, xmmword ptr [r11+rdx-3H*10H], 03H vshufps zmm4, zmm8, zmm9, 136 vshufps zmm5, zmm8, zmm9, 221 vmovups zmm8, zmmword ptr [r8+rdx-20H] vinserti32x4 zmm8, zmm8, xmmword ptr [r9+rdx-2H*10H], 01H vinserti32x4 zmm8, zmm8, xmmword ptr [r10+rdx-2H*10H], 02H vinserti32x4 zmm8, zmm8, xmmword ptr [r11+rdx-2H*10H], 03H vmovups zmm9, zmmword ptr [r8+rdx-10H] vinserti32x4 zmm9, zmm9, xmmword ptr [r9+rdx-1H*10H], 01H vinserti32x4 zmm9, zmm9, xmmword ptr [r10+rdx-1H*10H], 02H vinserti32x4 zmm9, zmm9, xmmword ptr [r11+rdx-1H*10H], 03H vshufps zmm6, zmm8, zmm9, 136 vshufps zmm7, zmm8, zmm9, 221 vpshufd zmm6, zmm6, 93H vpshufd zmm7, zmm7, 93H mov al, 7 roundloop4: vpaddd zmm0, zmm0, zmm4 vpaddd zmm0, zmm0, zmm1 vpxord zmm3, zmm3, zmm0 vprord zmm3, zmm3, 16 vpaddd zmm2, zmm2, zmm3 vpxord zmm1, zmm1, zmm2 vprord zmm1, zmm1, 12 vpaddd zmm0, zmm0, zmm5 vpaddd zmm0, zmm0, zmm1 vpxord zmm3, zmm3, zmm0 vprord zmm3, zmm3, 8 vpaddd zmm2, zmm2, zmm3 vpxord zmm1, zmm1, zmm2 vprord zmm1, zmm1, 7 vpshufd zmm0, zmm0, 93H vpshufd zmm3, zmm3, 4EH vpshufd zmm2, zmm2, 39H vpaddd zmm0, zmm0, zmm6 vpaddd zmm0, zmm0, zmm1 vpxord zmm3, zmm3, zmm0 vprord zmm3, zmm3, 16 vpaddd zmm2, zmm2, zmm3 vpxord zmm1, zmm1, zmm2 vprord zmm1, zmm1, 12 vpaddd zmm0, zmm0, zmm7 vpaddd zmm0, zmm0, zmm1 vpxord zmm3, zmm3, zmm0 vprord zmm3, zmm3, 8 vpaddd zmm2, zmm2, zmm3 vpxord zmm1, zmm1, zmm2 vprord zmm1, zmm1, 7 vpshufd zmm0, zmm0, 39H vpshufd zmm3, zmm3, 4EH vpshufd zmm2, zmm2, 93H dec al jz endroundloop4 vshufps zmm8, zmm4, zmm5, 214 vpshufd zmm9, zmm4, 0FH vpshufd zmm4, zmm8, 39H vshufps zmm8, zmm6, zmm7, 250 vpblendmd zmm9 {k3}, zmm9, zmm8 vpunpcklqdq zmm8, zmm7, zmm5 vpblendmd zmm8 {k4}, zmm8, zmm6 vpshufd zmm8, zmm8, 78H vpunpckhdq zmm5, zmm5, zmm7 vpunpckldq zmm6, zmm6, zmm5 vpshufd zmm7, zmm6, 1EH vmovdqa32 zmm5, zmm9 vmovdqa32 zmm6, zmm8 jmp roundloop4 endroundloop4: vpxord zmm0, zmm0, zmm2 vpxord zmm1, zmm1, zmm3 mov eax, r13d cmp rdx, r15 jne innerloop4 vmovdqu xmmword ptr [rbx], xmm0 vmovdqu xmmword ptr [rbx+10H], xmm1 vextracti128 xmmword ptr [rbx+20H], ymm0, 01H vextracti128 xmmword ptr [rbx+30H], ymm1, 01H vextracti32x4 xmmword ptr [rbx+4H*10H], zmm0, 02H vextracti32x4 xmmword ptr [rbx+5H*10H], zmm1, 02H vextracti32x4 xmmword ptr [rbx+6H*10H], zmm0, 03H vextracti32x4 xmmword ptr [rbx+7H*10H], zmm1, 03H vmovdqa xmm0, xmmword ptr [rsp] vmovdqa xmm2, xmmword ptr [rsp+40H] vmovdqa32 xmm0 {k1}, xmmword ptr [rsp+1H*10H] vmovdqa32 xmm2 {k1}, xmmword ptr [rsp+5H*10H] vmovdqa xmmword ptr [rsp], xmm0 vmovdqa xmmword ptr [rsp+40H], xmm2 add rbx, 128 add rdi, 32 sub rsi, 4 final3blocks: test esi, 2H je final1block vbroadcasti128 ymm0, xmmword ptr [rcx] vbroadcasti128 ymm1, xmmword ptr [rcx+10H] vmovd xmm13, dword ptr [rsp] vpinsrd xmm13, xmm13, dword ptr [rsp+40H], 1 vpinsrd xmm13, xmm13, dword ptr [BLAKE3_BLOCK_LEN], 2 vmovd xmm14, dword ptr [rsp+4H] vpinsrd xmm14, xmm14, dword ptr [rsp+44H], 1 vpinsrd xmm14, xmm14, dword ptr [BLAKE3_BLOCK_LEN], 2 vinserti128 ymm13, ymm13, xmm14, 01H mov r8, qword ptr [rdi] mov r9, qword ptr [rdi+8H] movzx eax, byte ptr [rbp+80H] or eax, r13d xor edx, edx ALIGN 16 innerloop2: mov r14d, eax or eax, r12d add rdx, 64 cmp rdx, r15 cmovne eax, r14d mov dword ptr [rsp+88H], eax vbroadcasti128 ymm2, xmmword ptr [BLAKE3_IV] vpbroadcastd ymm8, dword ptr [rsp+88H] vpblendd ymm3, ymm13, ymm8, 88H vmovups ymm8, ymmword ptr [r8+rdx-40H] vinsertf128 ymm8, ymm8, xmmword ptr [r9+rdx-40H], 01H vmovups ymm9, ymmword ptr [r8+rdx-30H] vinsertf128 ymm9, ymm9, xmmword ptr [r9+rdx-30H], 01H vshufps ymm4, ymm8, ymm9, 136 vshufps ymm5, ymm8, ymm9, 221 vmovups ymm8, ymmword ptr [r8+rdx-20H] vinsertf128 ymm8, ymm8, xmmword ptr [r9+rdx-20H], 01H vmovups ymm9, ymmword ptr [r8+rdx-10H] vinsertf128 ymm9, ymm9, xmmword ptr [r9+rdx-10H], 01H vshufps ymm6, ymm8, ymm9, 136 vshufps ymm7, ymm8, ymm9, 221 vpshufd ymm6, ymm6, 93H vpshufd ymm7, ymm7, 93H mov al, 7 roundloop2: vpaddd ymm0, ymm0, ymm4 vpaddd ymm0, ymm0, ymm1 vpxord ymm3, ymm3, ymm0 vprord ymm3, ymm3, 16 vpaddd ymm2, ymm2, ymm3 vpxord ymm1, ymm1, ymm2 vprord ymm1, ymm1, 12 vpaddd ymm0, ymm0, ymm5 vpaddd ymm0, ymm0, ymm1 vpxord ymm3, ymm3, ymm0 vprord ymm3, ymm3, 8 vpaddd ymm2, ymm2, ymm3 vpxord ymm1, ymm1, ymm2 vprord ymm1, ymm1, 7 vpshufd ymm0, ymm0, 93H vpshufd ymm3, ymm3, 4EH vpshufd ymm2, ymm2, 39H vpaddd ymm0, ymm0, ymm6 vpaddd ymm0, ymm0, ymm1 vpxord ymm3, ymm3, ymm0 vprord ymm3, ymm3, 16 vpaddd ymm2, ymm2, ymm3 vpxord ymm1, ymm1, ymm2 vprord ymm1, ymm1, 12 vpaddd ymm0, ymm0, ymm7 vpaddd ymm0, ymm0, ymm1 vpxord ymm3, ymm3, ymm0 vprord ymm3, ymm3, 8 vpaddd ymm2, ymm2, ymm3 vpxord ymm1, ymm1, ymm2 vprord ymm1, ymm1, 7 vpshufd ymm0, ymm0, 39H vpshufd ymm3, ymm3, 4EH vpshufd ymm2, ymm2, 93H dec al jz endroundloop2 vshufps ymm8, ymm4, ymm5, 214 vpshufd ymm9, ymm4, 0FH vpshufd ymm4, ymm8, 39H vshufps ymm8, ymm6, ymm7, 250 vpblendd ymm9, ymm9, ymm8, 0AAH vpunpcklqdq ymm8, ymm7, ymm5 vpblendd ymm8, ymm8, ymm6, 88H vpshufd ymm8, ymm8, 78H vpunpckhdq ymm5, ymm5, ymm7 vpunpckldq ymm6, ymm6, ymm5 vpshufd ymm7, ymm6, 1EH vmovdqa ymm5, ymm9 vmovdqa ymm6, ymm8 jmp roundloop2 endroundloop2: vpxor ymm0, ymm0, ymm2 vpxor ymm1, ymm1, ymm3 mov eax, r13d cmp rdx, r15 jne innerloop2 vmovdqu xmmword ptr [rbx], xmm0 vmovdqu xmmword ptr [rbx+10H], xmm1 vextracti128 xmmword ptr [rbx+20H], ymm0, 01H vextracti128 xmmword ptr [rbx+30H], ymm1, 01H vmovdqa xmm0, xmmword ptr [rsp] vmovdqa xmm2, xmmword ptr [rsp+40H] vmovdqu32 xmm0 {k1}, xmmword ptr [rsp+8H] vmovdqu32 xmm2 {k1}, xmmword ptr [rsp+48H] vmovdqa xmmword ptr [rsp], xmm0 vmovdqa xmmword ptr [rsp+40H], xmm2 add rbx, 64 add rdi, 16 sub rsi, 2 final1block: test esi, 1H je unwind vmovdqu xmm0, xmmword ptr [rcx] vmovdqu xmm1, xmmword ptr [rcx+10H] vmovd xmm14, dword ptr [rsp] vpinsrd xmm14, xmm14, dword ptr [rsp+40H], 1 vpinsrd xmm14, xmm14, dword ptr [BLAKE3_BLOCK_LEN], 2 vmovdqa xmm15, xmmword ptr [BLAKE3_IV] mov r8, qword ptr [rdi] movzx eax, byte ptr [rbp+80H] or eax, r13d xor edx, edx ALIGN 16 innerloop1: mov r14d, eax or eax, r12d add rdx, 64 cmp rdx, r15 cmovne eax, r14d vpinsrd xmm3, xmm14, eax, 3 vmovdqa xmm2, xmm15 vmovups xmm8, xmmword ptr [r8+rdx-40H] vmovups xmm9, xmmword ptr [r8+rdx-30H] vshufps xmm4, xmm8, xmm9, 136 vshufps xmm5, xmm8, xmm9, 221 vmovups xmm8, xmmword ptr [r8+rdx-20H] vmovups xmm9, xmmword ptr [r8+rdx-10H] vshufps xmm6, xmm8, xmm9, 136 vshufps xmm7, xmm8, xmm9, 221 vpshufd xmm6, xmm6, 93H vpshufd xmm7, xmm7, 93H mov al, 7 roundloop1: vpaddd xmm0, xmm0, xmm4 vpaddd xmm0, xmm0, xmm1 vpxord xmm3, xmm3, xmm0 vprord xmm3, xmm3, 16 vpaddd xmm2, xmm2, xmm3 vpxord xmm1, xmm1, xmm2 vprord xmm1, xmm1, 12 vpaddd xmm0, xmm0, xmm5 vpaddd xmm0, xmm0, xmm1 vpxord xmm3, xmm3, xmm0 vprord xmm3, xmm3, 8 vpaddd xmm2, xmm2, xmm3 vpxord xmm1, xmm1, xmm2 vprord xmm1, xmm1, 7 vpshufd xmm0, xmm0, 93H vpshufd xmm3, xmm3, 4EH vpshufd xmm2, xmm2, 39H vpaddd xmm0, xmm0, xmm6 vpaddd xmm0, xmm0, xmm1 vpxord xmm3, xmm3, xmm0 vprord xmm3, xmm3, 16 vpaddd xmm2, xmm2, xmm3 vpxord xmm1, xmm1, xmm2 vprord xmm1, xmm1, 12 vpaddd xmm0, xmm0, xmm7 vpaddd xmm0, xmm0, xmm1 vpxord xmm3, xmm3, xmm0 vprord xmm3, xmm3, 8 vpaddd xmm2, xmm2, xmm3 vpxord xmm1, xmm1, xmm2 vprord xmm1, xmm1, 7 vpshufd xmm0, xmm0, 39H vpshufd xmm3, xmm3, 4EH vpshufd xmm2, xmm2, 93H dec al jz endroundloop1 vshufps xmm8, xmm4, xmm5, 214 vpshufd xmm9, xmm4, 0FH vpshufd xmm4, xmm8, 39H vshufps xmm8, xmm6, xmm7, 250 vpblendd xmm9, xmm9, xmm8, 0AAH vpunpcklqdq xmm8, xmm7, xmm5 vpblendd xmm8, xmm8, xmm6, 88H vpshufd xmm8, xmm8, 78H vpunpckhdq xmm5, xmm5, xmm7 vpunpckldq xmm6, xmm6, xmm5 vpshufd xmm7, xmm6, 1EH vmovdqa xmm5, xmm9 vmovdqa xmm6, xmm8 jmp roundloop1 endroundloop1: vpxor xmm0, xmm0, xmm2 vpxor xmm1, xmm1, xmm3 mov eax, r13d cmp rdx, r15 jne innerloop1 vmovdqu xmmword ptr [rbx], xmm0 vmovdqu xmmword ptr [rbx+10H], xmm1 jmp unwind _blake3_hash_many_avx512 ENDP blake3_hash_many_avx512 ENDP ALIGN 16 blake3_compress_in_place_avx512 PROC _blake3_compress_in_place_avx512 PROC sub rsp, 72 vmovdqa xmmword ptr [rsp], xmm6 vmovdqa xmmword ptr [rsp+10H], xmm7 vmovdqa xmmword ptr [rsp+20H], xmm8 vmovdqa xmmword ptr [rsp+30H], xmm9 vmovdqu xmm0, xmmword ptr [rcx] vmovdqu xmm1, xmmword ptr [rcx+10H] movzx eax, byte ptr [rsp+70H] movzx r8d, r8b shl rax, 32 add r8, rax vmovq xmm3, r9 vmovq xmm4, r8 vpunpcklqdq xmm3, xmm3, xmm4 vmovaps xmm2, xmmword ptr [BLAKE3_IV] vmovups xmm8, xmmword ptr [rdx] vmovups xmm9, xmmword ptr [rdx+10H] vshufps xmm4, xmm8, xmm9, 136 vshufps xmm5, xmm8, xmm9, 221 vmovups xmm8, xmmword ptr [rdx+20H] vmovups xmm9, xmmword ptr [rdx+30H] vshufps xmm6, xmm8, xmm9, 136 vshufps xmm7, xmm8, xmm9, 221 vpshufd xmm6, xmm6, 93H vpshufd xmm7, xmm7, 93H mov al, 7 @@: vpaddd xmm0, xmm0, xmm4 vpaddd xmm0, xmm0, xmm1 vpxord xmm3, xmm3, xmm0 vprord xmm3, xmm3, 16 vpaddd xmm2, xmm2, xmm3 vpxord xmm1, xmm1, xmm2 vprord xmm1, xmm1, 12 vpaddd xmm0, xmm0, xmm5 vpaddd xmm0, xmm0, xmm1 vpxord xmm3, xmm3, xmm0 vprord xmm3, xmm3, 8 vpaddd xmm2, xmm2, xmm3 vpxord xmm1, xmm1, xmm2 vprord xmm1, xmm1, 7 vpshufd xmm0, xmm0, 93H vpshufd xmm3, xmm3, 4EH vpshufd xmm2, xmm2, 39H vpaddd xmm0, xmm0, xmm6 vpaddd xmm0, xmm0, xmm1 vpxord xmm3, xmm3, xmm0 vprord xmm3, xmm3, 16 vpaddd xmm2, xmm2, xmm3 vpxord xmm1, xmm1, xmm2 vprord xmm1, xmm1, 12 vpaddd xmm0, xmm0, xmm7 vpaddd xmm0, xmm0, xmm1 vpxord xmm3, xmm3, xmm0 vprord xmm3, xmm3, 8 vpaddd xmm2, xmm2, xmm3 vpxord xmm1, xmm1, xmm2 vprord xmm1, xmm1, 7 vpshufd xmm0, xmm0, 39H vpshufd xmm3, xmm3, 4EH vpshufd xmm2, xmm2, 93H dec al jz @F vshufps xmm8, xmm4, xmm5, 214 vpshufd xmm9, xmm4, 0FH vpshufd xmm4, xmm8, 39H vshufps xmm8, xmm6, xmm7, 250 vpblendd xmm9, xmm9, xmm8, 0AAH vpunpcklqdq xmm8, xmm7, xmm5 vpblendd xmm8, xmm8, xmm6, 88H vpshufd xmm8, xmm8, 78H vpunpckhdq xmm5, xmm5, xmm7 vpunpckldq xmm6, xmm6, xmm5 vpshufd xmm7, xmm6, 1EH vmovdqa xmm5, xmm9 vmovdqa xmm6, xmm8 jmp @B @@: vpxor xmm0, xmm0, xmm2 vpxor xmm1, xmm1, xmm3 vmovdqu xmmword ptr [rcx], xmm0 vmovdqu xmmword ptr [rcx+10H], xmm1 vmovdqa xmm6, xmmword ptr [rsp] vmovdqa xmm7, xmmword ptr [rsp+10H] vmovdqa xmm8, xmmword ptr [rsp+20H] vmovdqa xmm9, xmmword ptr [rsp+30H] add rsp, 72 ret _blake3_compress_in_place_avx512 ENDP blake3_compress_in_place_avx512 ENDP ALIGN 16 blake3_compress_xof_avx512 PROC _blake3_compress_xof_avx512 PROC sub rsp, 72 vmovdqa xmmword ptr [rsp], xmm6 vmovdqa xmmword ptr [rsp+10H], xmm7 vmovdqa xmmword ptr [rsp+20H], xmm8 vmovdqa xmmword ptr [rsp+30H], xmm9 vmovdqu xmm0, xmmword ptr [rcx] vmovdqu xmm1, xmmword ptr [rcx+10H] movzx eax, byte ptr [rsp+70H] movzx r8d, r8b mov r10, qword ptr [rsp+78H] shl rax, 32 add r8, rax vmovq xmm3, r9 vmovq xmm4, r8 vpunpcklqdq xmm3, xmm3, xmm4 vmovaps xmm2, xmmword ptr [BLAKE3_IV] vmovups xmm8, xmmword ptr [rdx] vmovups xmm9, xmmword ptr [rdx+10H] vshufps xmm4, xmm8, xmm9, 136 vshufps xmm5, xmm8, xmm9, 221 vmovups xmm8, xmmword ptr [rdx+20H] vmovups xmm9, xmmword ptr [rdx+30H] vshufps xmm6, xmm8, xmm9, 136 vshufps xmm7, xmm8, xmm9, 221 vpshufd xmm6, xmm6, 93H vpshufd xmm7, xmm7, 93H mov al, 7 @@: vpaddd xmm0, xmm0, xmm4 vpaddd xmm0, xmm0, xmm1 vpxord xmm3, xmm3, xmm0 vprord xmm3, xmm3, 16 vpaddd xmm2, xmm2, xmm3 vpxord xmm1, xmm1, xmm2 vprord xmm1, xmm1, 12 vpaddd xmm0, xmm0, xmm5 vpaddd xmm0, xmm0, xmm1 vpxord xmm3, xmm3, xmm0 vprord xmm3, xmm3, 8 vpaddd xmm2, xmm2, xmm3 vpxord xmm1, xmm1, xmm2 vprord xmm1, xmm1, 7 vpshufd xmm0, xmm0, 93H vpshufd xmm3, xmm3, 4EH vpshufd xmm2, xmm2, 39H vpaddd xmm0, xmm0, xmm6 vpaddd xmm0, xmm0, xmm1 vpxord xmm3, xmm3, xmm0 vprord xmm3, xmm3, 16 vpaddd xmm2, xmm2, xmm3 vpxord xmm1, xmm1, xmm2 vprord xmm1, xmm1, 12 vpaddd xmm0, xmm0, xmm7 vpaddd xmm0, xmm0, xmm1 vpxord xmm3, xmm3, xmm0 vprord xmm3, xmm3, 8 vpaddd xmm2, xmm2, xmm3 vpxord xmm1, xmm1, xmm2 vprord xmm1, xmm1, 7 vpshufd xmm0, xmm0, 39H vpshufd xmm3, xmm3, 4EH vpshufd xmm2, xmm2, 93H dec al jz @F vshufps xmm8, xmm4, xmm5, 214 vpshufd xmm9, xmm4, 0FH vpshufd xmm4, xmm8, 39H vshufps xmm8, xmm6, xmm7, 250 vpblendd xmm9, xmm9, xmm8, 0AAH vpunpcklqdq xmm8, xmm7, xmm5 vpblendd xmm8, xmm8, xmm6, 88H vpshufd xmm8, xmm8, 78H vpunpckhdq xmm5, xmm5, xmm7 vpunpckldq xmm6, xmm6, xmm5 vpshufd xmm7, xmm6, 1EH vmovdqa xmm5, xmm9 vmovdqa xmm6, xmm8 jmp @B @@: vpxor xmm0, xmm0, xmm2 vpxor xmm1, xmm1, xmm3 vpxor xmm2, xmm2, xmmword ptr [rcx] vpxor xmm3, xmm3, xmmword ptr [rcx+10H] vmovdqu xmmword ptr [r10], xmm0 vmovdqu xmmword ptr [r10+10H], xmm1 vmovdqu xmmword ptr [r10+20H], xmm2 vmovdqu xmmword ptr [r10+30H], xmm3 vmovdqa xmm6, xmmword ptr [rsp] vmovdqa xmm7, xmmword ptr [rsp+10H] vmovdqa xmm8, xmmword ptr [rsp+20H] vmovdqa xmm9, xmmword ptr [rsp+30H] add rsp, 72 ret _blake3_compress_xof_avx512 ENDP blake3_compress_xof_avx512 ENDP _TEXT ENDS _RDATA SEGMENT READONLY PAGE ALIAS(".rdata") 'CONST' ALIGN 64 INDEX0: dd 0, 1, 2, 3, 16, 17, 18, 19 dd 8, 9, 10, 11, 24, 25, 26, 27 INDEX1: dd 4, 5, 6, 7, 20, 21, 22, 23 dd 12, 13, 14, 15, 28, 29, 30, 31 ADD0: dd 0, 1, 2, 3, 4, 5, 6, 7 dd 8, 9, 10, 11, 12, 13, 14, 15 ADD1: dd 1 ADD16: dd 16 BLAKE3_BLOCK_LEN: dd 64 ALIGN 64 BLAKE3_IV: BLAKE3_IV_0: dd 06A09E667H BLAKE3_IV_1: dd 0BB67AE85H BLAKE3_IV_2: dd 03C6EF372H BLAKE3_IV_3: dd 0A54FF53AH _RDATA ENDS END librecast/libs/blake3/c/blake3_c_rust_bindings/000077500000000000000000000000001502456746400217545ustar00rootroot00000000000000librecast/libs/blake3/c/blake3_c_rust_bindings/Cargo.toml000066400000000000000000000020201502456746400236760ustar00rootroot00000000000000# These are Rust bindings for the C implementation of BLAKE3. As there is a # native (and faster) Rust implementation of BLAKE3 provided in this same repo, # these bindings are not expected to be used in production. They're intended # for testing and benchmarking. [package] name = "blake3_c_rust_bindings" version = "0.0.0" description = "TESTING ONLY Rust bindings for the BLAKE3 C implementation" edition = "2021" [features] # By default the x86-64 build uses assembly implementations. This feature makes # the build use the C intrinsics implementations instead. prefer_intrinsics = [] # Activate NEON bindings. We don't currently do any CPU feature detection for # this. If this Cargo feature is on, the NEON gets used. neon = [] # Enable TBB-based multithreading. tbb = [] [dev-dependencies] arrayref = "0.3.5" arrayvec = { version = "0.7.0", default-features = false } page_size = "0.6.0" rand = "0.9.0" rand_chacha = "0.9.0" reference_impl = { path = "../../reference_impl" } [build-dependencies] cc = "1.0.48" ignore = "0.4.23" librecast/libs/blake3/c/blake3_c_rust_bindings/README.md000066400000000000000000000003641502456746400232360ustar00rootroot00000000000000These are Rust bindings for the C implementation of BLAKE3. As there is a native Rust implementation of BLAKE3 provided in this same repo, these bindings are not expected to be used in production. They're intended for testing and benchmarking. librecast/libs/blake3/c/blake3_c_rust_bindings/benches/000077500000000000000000000000001502456746400233635ustar00rootroot00000000000000librecast/libs/blake3/c/blake3_c_rust_bindings/benches/bench.rs000066400000000000000000000262641502456746400250220ustar00rootroot00000000000000#![feature(test)] extern crate test; use arrayref::array_ref; use arrayvec::ArrayVec; use rand::prelude::*; use test::Bencher; const KIB: usize = 1024; const MAX_SIMD_DEGREE: usize = 16; const BLOCK_LEN: usize = 64; const CHUNK_LEN: usize = 1024; const OUT_LEN: usize = 32; // This struct randomizes two things: // 1. The actual bytes of input. // 2. The page offset the input starts at. pub struct RandomInput { buf: Vec, len: usize, offsets: Vec, offset_index: usize, } impl RandomInput { pub fn new(b: &mut Bencher, len: usize) -> Self { b.bytes += len as u64; let page_size: usize = page_size::get(); let mut buf = vec![0u8; len + page_size]; let mut rng = rand::rng(); rng.fill_bytes(&mut buf); let mut offsets: Vec = (0..page_size).collect(); offsets.shuffle(&mut rng); Self { buf, len, offsets, offset_index: 0, } } pub fn get(&mut self) -> &[u8] { let offset = self.offsets[self.offset_index]; self.offset_index += 1; if self.offset_index >= self.offsets.len() { self.offset_index = 0; } &self.buf[offset..][..self.len] } } type CompressInPlaceFn = unsafe extern "C" fn(cv: *mut u32, block: *const u8, block_len: u8, counter: u64, flags: u8); fn bench_single_compression_fn(b: &mut Bencher, f: CompressInPlaceFn) { let mut state = [1u32; 8]; let mut r = RandomInput::new(b, 64); let input = array_ref!(r.get(), 0, 64); b.iter(|| unsafe { f(state.as_mut_ptr(), input.as_ptr(), 64, 0, 0) }); } #[bench] fn bench_single_compression_portable(b: &mut Bencher) { bench_single_compression_fn( b, blake3_c_rust_bindings::ffi::blake3_compress_in_place_portable, ); } #[bench] #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] fn bench_single_compression_sse2(b: &mut Bencher) { if !blake3_c_rust_bindings::sse2_detected() { return; } bench_single_compression_fn( b, blake3_c_rust_bindings::ffi::x86::blake3_compress_in_place_sse2, ); } #[bench] #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] fn bench_single_compression_sse41(b: &mut Bencher) { if !blake3_c_rust_bindings::sse41_detected() { return; } bench_single_compression_fn( b, blake3_c_rust_bindings::ffi::x86::blake3_compress_in_place_sse41, ); } #[bench] fn bench_single_compression_avx512(b: &mut Bencher) { if !blake3_c_rust_bindings::avx512_detected() { return; } bench_single_compression_fn( b, blake3_c_rust_bindings::ffi::x86::blake3_compress_in_place_avx512, ); } type HashManyFn = unsafe extern "C" fn( inputs: *const *const u8, num_inputs: usize, blocks: usize, key: *const u32, counter: u64, increment_counter: bool, flags: u8, flags_start: u8, flags_end: u8, out: *mut u8, ); fn bench_many_chunks_fn(b: &mut Bencher, f: HashManyFn, degree: usize) { let mut inputs = Vec::new(); for _ in 0..degree { inputs.push(RandomInput::new(b, CHUNK_LEN)); } b.iter(|| { let input_arrays: ArrayVec<&[u8; CHUNK_LEN], MAX_SIMD_DEGREE> = inputs .iter_mut() .take(degree) .map(|i| array_ref!(i.get(), 0, CHUNK_LEN)) .collect(); let mut out = [0; MAX_SIMD_DEGREE * OUT_LEN]; unsafe { f( input_arrays.as_ptr() as _, input_arrays.len(), CHUNK_LEN / BLOCK_LEN, [0u32; 8].as_ptr(), 0, true, 0, 0, 0, out.as_mut_ptr(), ) } }); } #[bench] #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] fn bench_many_chunks_sse2(b: &mut Bencher) { if !blake3_c_rust_bindings::sse2_detected() { return; } bench_many_chunks_fn( b, blake3_c_rust_bindings::ffi::x86::blake3_hash_many_sse2, 4, ); } #[bench] #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] fn bench_many_chunks_sse41(b: &mut Bencher) { if !blake3_c_rust_bindings::sse41_detected() { return; } bench_many_chunks_fn( b, blake3_c_rust_bindings::ffi::x86::blake3_hash_many_sse41, 4, ); } #[bench] #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] fn bench_many_chunks_avx2(b: &mut Bencher) { if !blake3_c_rust_bindings::avx2_detected() { return; } bench_many_chunks_fn( b, blake3_c_rust_bindings::ffi::x86::blake3_hash_many_avx2, 8, ); } #[bench] fn bench_many_chunks_avx512(b: &mut Bencher) { if !blake3_c_rust_bindings::avx512_detected() { return; } bench_many_chunks_fn( b, blake3_c_rust_bindings::ffi::x86::blake3_hash_many_avx512, 16, ); } #[bench] #[cfg(feature = "neon")] fn bench_many_chunks_neon(b: &mut Bencher) { // When "neon" is on, NEON support is assumed. bench_many_chunks_fn( b, blake3_c_rust_bindings::ffi::neon::blake3_hash_many_neon, 4, ); } // TODO: When we get const generics we can unify this with the chunks code. fn bench_many_parents_fn(b: &mut Bencher, f: HashManyFn, degree: usize) { let mut inputs = Vec::new(); for _ in 0..degree { inputs.push(RandomInput::new(b, BLOCK_LEN)); } b.iter(|| { let input_arrays: ArrayVec<&[u8; BLOCK_LEN], MAX_SIMD_DEGREE> = inputs .iter_mut() .take(degree) .map(|i| array_ref!(i.get(), 0, BLOCK_LEN)) .collect(); let mut out = [0; MAX_SIMD_DEGREE * OUT_LEN]; unsafe { f( input_arrays.as_ptr() as _, input_arrays.len(), 1, [0u32; 8].as_ptr(), 0, false, 0, 0, 0, out.as_mut_ptr(), ) } }); } #[bench] #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] fn bench_many_parents_sse2(b: &mut Bencher) { if !blake3_c_rust_bindings::sse2_detected() { return; } bench_many_parents_fn( b, blake3_c_rust_bindings::ffi::x86::blake3_hash_many_sse2, 4, ); } #[bench] #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] fn bench_many_parents_sse41(b: &mut Bencher) { if !blake3_c_rust_bindings::sse41_detected() { return; } bench_many_parents_fn( b, blake3_c_rust_bindings::ffi::x86::blake3_hash_many_sse41, 4, ); } #[bench] #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] fn bench_many_parents_avx2(b: &mut Bencher) { if !blake3_c_rust_bindings::avx2_detected() { return; } bench_many_parents_fn( b, blake3_c_rust_bindings::ffi::x86::blake3_hash_many_avx2, 8, ); } #[bench] fn bench_many_parents_avx512(b: &mut Bencher) { if !blake3_c_rust_bindings::avx512_detected() { return; } bench_many_parents_fn( b, blake3_c_rust_bindings::ffi::x86::blake3_hash_many_avx512, 16, ); } #[bench] #[cfg(feature = "neon")] fn bench_many_parents_neon(b: &mut Bencher) { // When "neon" is on, NEON support is assumed. bench_many_parents_fn( b, blake3_c_rust_bindings::ffi::neon::blake3_hash_many_neon, 4, ); } fn bench_incremental(b: &mut Bencher, len: usize) { let mut input = RandomInput::new(b, len); b.iter(|| { let mut hasher = blake3_c_rust_bindings::Hasher::new(); hasher.update(input.get()); let mut out = [0; 32]; hasher.finalize(&mut out); out }); } #[bench] fn bench_incremental_0001_block(b: &mut Bencher) { bench_incremental(b, BLOCK_LEN); } #[bench] fn bench_incremental_0001_kib(b: &mut Bencher) { bench_incremental(b, 1 * KIB); } #[bench] fn bench_incremental_0002_kib(b: &mut Bencher) { bench_incremental(b, 2 * KIB); } #[bench] fn bench_incremental_0004_kib(b: &mut Bencher) { bench_incremental(b, 4 * KIB); } #[bench] fn bench_incremental_0008_kib(b: &mut Bencher) { bench_incremental(b, 8 * KIB); } #[bench] fn bench_incremental_0016_kib(b: &mut Bencher) { bench_incremental(b, 16 * KIB); } #[bench] fn bench_incremental_0032_kib(b: &mut Bencher) { bench_incremental(b, 32 * KIB); } #[bench] fn bench_incremental_0064_kib(b: &mut Bencher) { bench_incremental(b, 64 * KIB); } #[bench] fn bench_incremental_0128_kib(b: &mut Bencher) { bench_incremental(b, 128 * KIB); } #[bench] fn bench_incremental_0256_kib(b: &mut Bencher) { bench_incremental(b, 256 * KIB); } #[bench] fn bench_incremental_0512_kib(b: &mut Bencher) { bench_incremental(b, 512 * KIB); } #[bench] fn bench_incremental_1024_kib(b: &mut Bencher) { bench_incremental(b, 1024 * KIB); } #[cfg(feature = "tbb")] fn bench_tbb(b: &mut Bencher, len: usize) { let mut input = RandomInput::new(b, len); b.iter(|| { let mut hasher = blake3_c_rust_bindings::Hasher::new(); hasher.update_tbb(input.get()); let mut out = [0; 32]; hasher.finalize(&mut out); out }); } #[bench] #[cfg(feature = "tbb")] fn bench_tbb_0001_block(b: &mut Bencher) { bench_tbb(b, BLOCK_LEN); } #[bench] #[cfg(feature = "tbb")] fn bench_tbb_0001_kib(b: &mut Bencher) { bench_tbb(b, 1 * KIB); } #[bench] #[cfg(feature = "tbb")] fn bench_tbb_0002_kib(b: &mut Bencher) { bench_tbb(b, 2 * KIB); } #[bench] #[cfg(feature = "tbb")] fn bench_tbb_0004_kib(b: &mut Bencher) { bench_tbb(b, 4 * KIB); } #[bench] #[cfg(feature = "tbb")] fn bench_tbb_0008_kib(b: &mut Bencher) { bench_tbb(b, 8 * KIB); } #[bench] #[cfg(feature = "tbb")] fn bench_tbb_0016_kib(b: &mut Bencher) { bench_tbb(b, 16 * KIB); } #[bench] #[cfg(feature = "tbb")] fn bench_tbb_0032_kib(b: &mut Bencher) { bench_tbb(b, 32 * KIB); } #[bench] #[cfg(feature = "tbb")] fn bench_tbb_0064_kib(b: &mut Bencher) { bench_tbb(b, 64 * KIB); } #[bench] #[cfg(feature = "tbb")] fn bench_tbb_0128_kib(b: &mut Bencher) { bench_tbb(b, 128 * KIB); } #[bench] #[cfg(feature = "tbb")] fn bench_tbb_0256_kib(b: &mut Bencher) { bench_tbb(b, 256 * KIB); } #[bench] #[cfg(feature = "tbb")] fn bench_tbb_0512_kib(b: &mut Bencher) { bench_tbb(b, 512 * KIB); } #[bench] #[cfg(feature = "tbb")] fn bench_tbb_1024_kib(b: &mut Bencher) { bench_tbb(b, 1024 * KIB); } // This checks that update() splits up its input in increasing powers of 2, so // that it can recover a high degree of parallelism when the number of bytes // hashed so far is uneven. The performance of this benchmark should be // reasonably close to bench_incremental_0064_kib, within 80% or so. When we // had a bug in this logic (https://github.com/BLAKE3-team/BLAKE3/issues/69), // performance was less than half. #[bench] fn bench_two_updates(b: &mut Bencher) { let len = 65536; let mut input = RandomInput::new(b, len); b.iter(|| { let mut hasher = blake3_c_rust_bindings::Hasher::new(); let input = input.get(); hasher.update(&input[..1]); hasher.update(&input[1..]); let mut out = [0; 32]; hasher.finalize(&mut out); out }); } librecast/libs/blake3/c/blake3_c_rust_bindings/build.rs000066400000000000000000000234601502456746400234260ustar00rootroot00000000000000use std::env; fn defined(var: &str) -> bool { env::var_os(var).is_some() } fn target_components() -> Vec { let target = env::var("TARGET").unwrap(); target.split("-").map(|s| s.to_string()).collect() } fn is_x86_64() -> bool { target_components()[0] == "x86_64" } fn is_windows_target() -> bool { env::var("CARGO_CFG_TARGET_OS").unwrap() == "windows" } fn use_msvc_asm() -> bool { const MSVC_NAMES: &[&str] = &["", "cl", "cl.exe"]; let target_os = env::var("CARGO_CFG_TARGET_OS").unwrap_or_default(); let target_env = env::var("CARGO_CFG_TARGET_ENV").unwrap_or_default(); let target_windows_msvc = target_os == "windows" && target_env == "msvc"; let host_triple = env::var("HOST").unwrap_or_default(); let target_triple = env::var("TARGET").unwrap_or_default(); let cross_compiling = host_triple != target_triple; let cc = env::var("CC").unwrap_or_default().to_ascii_lowercase(); if !target_windows_msvc { // We are not building for Windows with the MSVC toolchain. false } else if !cross_compiling && MSVC_NAMES.contains(&&*cc) { // We are building on Windows with the MSVC toolchain (and not cross-compiling for another architecture or target). true } else { // We are cross-compiling to Windows with the MSVC toolchain. let target_arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap_or_default(); let target_vendor = env::var("CARGO_CFG_TARGET_VENDOR").unwrap_or_default(); let cc = env::var(format!("CC_{target_arch}_{target_vendor}_windows_msvc")) .unwrap_or_default() .to_ascii_lowercase(); // Check if we are using the MSVC compiler. MSVC_NAMES.contains(&&*cc) } } fn is_x86_32() -> bool { let arch = &target_components()[0]; arch == "i386" || arch == "i586" || arch == "i686" } fn is_armv7() -> bool { target_components()[0] == "armv7" } fn is_aarch64() -> bool { target_components()[0] == "aarch64" } // Windows targets may be using the MSVC toolchain or the GNU toolchain. The // right compiler flags to use depend on the toolchain. (And we don't want to // use flag_if_supported, because we don't want features to be silently // disabled by old compilers.) fn is_windows_msvc() -> bool { // Some targets are only two components long, so check in steps. target_components()[1] == "pc" && target_components()[2] == "windows" && target_components()[3] == "msvc" } fn new_build() -> cc::Build { let mut build = cc::Build::new(); if !is_windows_msvc() { build.flag("-std=c11"); } build } fn new_cpp_build() -> cc::Build { let mut build = cc::Build::new(); build.cpp(true); if is_windows_msvc() { build.flag("/std:c++20"); build.flag("/EHs-c-"); build.flag("/GR-"); } else { build.flag("-std=c++20"); build.flag("-fno-exceptions"); build.flag("-fno-rtti"); } build } fn c_dir_path(filename: &str) -> String { // The `cross` tool doesn't support reading files in parent directories. As a hacky workaround // in `cross_test.sh`, we move the c/ directory around and set BLAKE3_C_DIR_OVERRIDE. Regular // building and testing doesn't require this. if let Ok(c_dir_override) = env::var("BLAKE3_C_DIR_OVERRIDE") { c_dir_override + "/" + filename } else { "../".to_string() + filename } } fn main() -> Result<(), Box> { let mut base_build = new_build(); base_build.file(c_dir_path("blake3.c")); base_build.file(c_dir_path("blake3_dispatch.c")); base_build.file(c_dir_path("blake3_portable.c")); if cfg!(feature = "tbb") { base_build.define("BLAKE3_USE_TBB", "1"); } base_build.compile("blake3_base"); if cfg!(feature = "tbb") { let mut tbb_build = new_cpp_build(); tbb_build.define("BLAKE3_USE_TBB", "1"); tbb_build.file(c_dir_path("blake3_tbb.cpp")); tbb_build.compile("blake3_tbb"); println!("cargo::rustc-link-lib=tbb"); } if is_x86_64() && !defined("CARGO_FEATURE_PREFER_INTRINSICS") { // On 64-bit, use the assembly implementations, unless the // "prefer_intrinsics" feature is enabled. if is_windows_target() { if use_msvc_asm() { let mut build = new_build(); build.file(c_dir_path("blake3_sse2_x86-64_windows_msvc.asm")); build.file(c_dir_path("blake3_sse41_x86-64_windows_msvc.asm")); build.file(c_dir_path("blake3_avx2_x86-64_windows_msvc.asm")); build.file(c_dir_path("blake3_avx512_x86-64_windows_msvc.asm")); build.compile("blake3_asm"); } else { let mut build = new_build(); build.file(c_dir_path("blake3_sse2_x86-64_windows_gnu.S")); build.file(c_dir_path("blake3_sse41_x86-64_windows_gnu.S")); build.file(c_dir_path("blake3_avx2_x86-64_windows_gnu.S")); build.file(c_dir_path("blake3_avx512_x86-64_windows_gnu.S")); build.compile("blake3_asm"); } } else { // All non-Windows implementations are assumed to support // Linux-style assembly. These files do contain a small // explicit workaround for macOS also. let mut build = new_build(); build.file(c_dir_path("blake3_sse2_x86-64_unix.S")); build.file(c_dir_path("blake3_sse41_x86-64_unix.S")); build.file(c_dir_path("blake3_avx2_x86-64_unix.S")); build.file(c_dir_path("blake3_avx512_x86-64_unix.S")); build.compile("blake3_asm"); } } else if is_x86_64() || is_x86_32() { // Assembly implementations are only for 64-bit. On 32-bit, or if // the "prefer_intrinsics" feature is enabled, use the // intrinsics-based C implementations. These each need to be // compiled separately, with the corresponding instruction set // extension explicitly enabled in the compiler. let mut sse2_build = new_build(); sse2_build.file(c_dir_path("blake3_sse2.c")); if is_windows_msvc() { // /arch:SSE2 is the default on x86 and undefined on x86_64: // https://docs.microsoft.com/en-us/cpp/build/reference/arch-x86 // It also includes SSE4.1 intrinsics: // https://stackoverflow.com/a/32183222/823869 } else { sse2_build.flag("-msse2"); } sse2_build.compile("blake3_sse2"); let mut sse41_build = new_build(); sse41_build.file(c_dir_path("blake3_sse41.c")); if is_windows_msvc() { // /arch:SSE2 is the default on x86 and undefined on x86_64: // https://docs.microsoft.com/en-us/cpp/build/reference/arch-x86 // It also includes SSE4.1 intrinsics: // https://stackoverflow.com/a/32183222/823869 } else { sse41_build.flag("-msse4.1"); } sse41_build.compile("blake3_sse41"); let mut avx2_build = new_build(); avx2_build.file(c_dir_path("blake3_avx2.c")); if is_windows_msvc() { avx2_build.flag("/arch:AVX2"); } else { avx2_build.flag("-mavx2"); } avx2_build.compile("blake3_avx2"); let mut avx512_build = new_build(); avx512_build.file(c_dir_path("blake3_avx512.c")); if is_windows_msvc() { // Note that a lot of versions of MSVC don't support /arch:AVX512, // and they'll discard it with a warning, hopefully leading to a // build error. avx512_build.flag("/arch:AVX512"); } else { avx512_build.flag("-mavx512f"); avx512_build.flag("-mavx512vl"); } avx512_build.compile("blake3_avx512"); } // We only build NEON code here if // 1) it's requested // and 2) the root crate is not already building it. // The only time this will really happen is if you build this // crate by hand with the "neon" feature for some reason. // // In addition, 3) if the target is aarch64, NEON is on by default. if defined("CARGO_FEATURE_NEON") || is_aarch64() { let mut neon_build = new_build(); neon_build.file(c_dir_path("blake3_neon.c")); // ARMv7 platforms that support NEON generally need the following // flags. AArch64 supports NEON by default and does not support -mpfu. if is_armv7() { neon_build.flag("-mfpu=neon-vfpv4"); neon_build.flag("-mfloat-abi=hard"); } neon_build.compile("blake3_neon"); } // The `cc` crate does not automatically emit rerun-if directives for the // environment variables it supports, in particular for $CC. We expect to // do a lot of benchmarking across different compilers, so we explicitly // add the variables that we're likely to need. println!("cargo:rerun-if-env-changed=CC"); println!("cargo:rerun-if-env-changed=CFLAGS"); // Ditto for source files, though these shouldn't change as often. `ignore::Walk` respects // .gitignore, so this doesn't traverse target/. for result in ignore::Walk::new("..") { let result = result?; let path = result.path(); if path.is_file() { println!("cargo:rerun-if-changed={}", path.to_str().unwrap()); } } // When compiling with clang-cl for windows, it adds .asm files to the root // which we need to delete so cargo doesn't get angry if is_windows_target() && !use_msvc_asm() { let _ = std::fs::remove_file("blake3_avx2_x86-64_windows_gnu.asm"); let _ = std::fs::remove_file("blake3_avx512_x86-64_windows_gnu.asm"); let _ = std::fs::remove_file("blake3_sse2_x86-64_windows_gnu.asm"); let _ = std::fs::remove_file("blake3_sse41_x86-64_windows_gnu.asm"); } Ok(()) } librecast/libs/blake3/c/blake3_c_rust_bindings/cross_test.sh000077500000000000000000000021471502456746400245070ustar00rootroot00000000000000#! /usr/bin/env bash # This hacky script works around the fact that `cross test` does not support # path dependencies. (It uses a docker shared folder to let the guest access # project files, so parent directories aren't available.) Solve this problem by # copying the entire project to a temp dir and rearranging paths to put "c" and # "reference_impl" underneath "blake3_c_rust_bindings", so that everything is # accessible. Hopefully this will just run on CI forever and no one will ever # read this and discover my deep shame. set -e -u -o pipefail project_root="$(realpath "$(dirname "$BASH_SOURCE")/../..")" tmpdir="$(mktemp -d)" echo "Running cross tests in $tmpdir" cd "$tmpdir" git clone "$project_root" blake3 mv blake3/c/blake3_c_rust_bindings . mv blake3/reference_impl blake3_c_rust_bindings mv blake3/c blake3_c_rust_bindings cd blake3_c_rust_bindings sed -i 's|reference_impl = { path = "../../reference_impl" }|reference_impl = { path = "reference_impl" }|' Cargo.toml export BLAKE3_C_DIR_OVERRIDE="./c" cat > Cross.toml << EOF [build.env] passthrough = [ "BLAKE3_C_DIR_OVERRIDE", ] EOF cross test "$@" librecast/libs/blake3/c/blake3_c_rust_bindings/src/000077500000000000000000000000001502456746400225435ustar00rootroot00000000000000librecast/libs/blake3/c/blake3_c_rust_bindings/src/lib.rs000066400000000000000000000233111502456746400236570ustar00rootroot00000000000000//! These are Rust bindings for the C implementation of BLAKE3. As there is a //! native (and faster) Rust implementation of BLAKE3 provided in this same //! repo, these bindings are not expected to be used in production. They're //! intended for testing and benchmarking. use std::ffi::{c_void, CString}; use std::mem::MaybeUninit; #[cfg(test)] mod test; pub const BLOCK_LEN: usize = 64; pub const CHUNK_LEN: usize = 1024; pub const OUT_LEN: usize = 32; // Feature detection functions for tests and benchmarks. Note that the C code // does its own feature detection in blake3_dispatch.c. #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] pub fn sse2_detected() -> bool { is_x86_feature_detected!("sse2") } #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] pub fn sse41_detected() -> bool { is_x86_feature_detected!("sse4.1") } #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] pub fn avx2_detected() -> bool { is_x86_feature_detected!("avx2") } #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] pub fn avx512_detected() -> bool { is_x86_feature_detected!("avx512f") && is_x86_feature_detected!("avx512vl") } #[derive(Clone)] pub struct Hasher(ffi::blake3_hasher); impl Hasher { pub fn new() -> Self { let mut c_state = MaybeUninit::uninit(); unsafe { ffi::blake3_hasher_init(c_state.as_mut_ptr()); Self(c_state.assume_init()) } } pub fn new_keyed(key: &[u8; 32]) -> Self { let mut c_state = MaybeUninit::uninit(); unsafe { ffi::blake3_hasher_init_keyed(c_state.as_mut_ptr(), key.as_ptr()); Self(c_state.assume_init()) } } pub fn new_derive_key(context: &str) -> Self { let mut c_state = MaybeUninit::uninit(); let context_c_string = CString::new(context).expect("valid C string, no null bytes"); unsafe { ffi::blake3_hasher_init_derive_key(c_state.as_mut_ptr(), context_c_string.as_ptr()); Self(c_state.assume_init()) } } pub fn new_derive_key_raw(context: &[u8]) -> Self { let mut c_state = MaybeUninit::uninit(); unsafe { ffi::blake3_hasher_init_derive_key_raw( c_state.as_mut_ptr(), context.as_ptr() as *const _, context.len(), ); Self(c_state.assume_init()) } } pub fn update(&mut self, input: &[u8]) { unsafe { ffi::blake3_hasher_update(&mut self.0, input.as_ptr() as *const c_void, input.len()); } } #[cfg(feature = "tbb")] pub fn update_tbb(&mut self, input: &[u8]) { unsafe { ffi::blake3_hasher_update_tbb( &mut self.0, input.as_ptr() as *const c_void, input.len(), ); } } pub fn finalize(&self, output: &mut [u8]) { unsafe { ffi::blake3_hasher_finalize(&self.0, output.as_mut_ptr(), output.len()); } } pub fn finalize_seek(&self, seek: u64, output: &mut [u8]) { unsafe { ffi::blake3_hasher_finalize_seek(&self.0, seek, output.as_mut_ptr(), output.len()); } } pub fn reset(&mut self) { unsafe { ffi::blake3_hasher_reset(&mut self.0); } } } pub mod ffi { #[repr(C)] #[derive(Copy, Clone)] pub struct blake3_chunk_state { pub cv: [u32; 8usize], pub chunk_counter: u64, pub buf: [u8; 64usize], pub buf_len: u8, pub blocks_compressed: u8, pub flags: u8, } #[repr(C)] #[derive(Copy, Clone)] pub struct blake3_hasher { pub key: [u32; 8usize], pub chunk: blake3_chunk_state, pub cv_stack_len: u8, pub cv_stack: [u8; 1728usize], } extern "C" { // public interface pub fn blake3_hasher_init(self_: *mut blake3_hasher); pub fn blake3_hasher_init_keyed(self_: *mut blake3_hasher, key: *const u8); pub fn blake3_hasher_init_derive_key( self_: *mut blake3_hasher, context: *const ::std::os::raw::c_char, ); pub fn blake3_hasher_init_derive_key_raw( self_: *mut blake3_hasher, context: *const ::std::os::raw::c_void, context_len: usize, ); pub fn blake3_hasher_update( self_: *mut blake3_hasher, input: *const ::std::os::raw::c_void, input_len: usize, ); #[cfg(feature = "tbb")] pub fn blake3_hasher_update_tbb( self_: *mut blake3_hasher, input: *const ::std::os::raw::c_void, input_len: usize, ); pub fn blake3_hasher_finalize(self_: *const blake3_hasher, out: *mut u8, out_len: usize); pub fn blake3_hasher_finalize_seek( self_: *const blake3_hasher, seek: u64, out: *mut u8, out_len: usize, ); pub fn blake3_hasher_reset(self_: *mut blake3_hasher); // portable low-level functions pub fn blake3_compress_in_place_portable( cv: *mut u32, block: *const u8, block_len: u8, counter: u64, flags: u8, ); pub fn blake3_compress_xof_portable( cv: *const u32, block: *const u8, block_len: u8, counter: u64, flags: u8, out: *mut u8, ); pub fn blake3_hash_many_portable( inputs: *const *const u8, num_inputs: usize, blocks: usize, key: *const u32, counter: u64, increment_counter: bool, flags: u8, flags_start: u8, flags_end: u8, out: *mut u8, ); } #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] pub mod x86 { extern "C" { // SSE2 low level functions pub fn blake3_compress_in_place_sse2( cv: *mut u32, block: *const u8, block_len: u8, counter: u64, flags: u8, ); pub fn blake3_compress_xof_sse2( cv: *const u32, block: *const u8, block_len: u8, counter: u64, flags: u8, out: *mut u8, ); pub fn blake3_hash_many_sse2( inputs: *const *const u8, num_inputs: usize, blocks: usize, key: *const u32, counter: u64, increment_counter: bool, flags: u8, flags_start: u8, flags_end: u8, out: *mut u8, ); // SSE4.1 low level functions pub fn blake3_compress_in_place_sse41( cv: *mut u32, block: *const u8, block_len: u8, counter: u64, flags: u8, ); pub fn blake3_compress_xof_sse41( cv: *const u32, block: *const u8, block_len: u8, counter: u64, flags: u8, out: *mut u8, ); pub fn blake3_hash_many_sse41( inputs: *const *const u8, num_inputs: usize, blocks: usize, key: *const u32, counter: u64, increment_counter: bool, flags: u8, flags_start: u8, flags_end: u8, out: *mut u8, ); // AVX2 low level functions pub fn blake3_hash_many_avx2( inputs: *const *const u8, num_inputs: usize, blocks: usize, key: *const u32, counter: u64, increment_counter: bool, flags: u8, flags_start: u8, flags_end: u8, out: *mut u8, ); // AVX-512 low level functions pub fn blake3_compress_xof_avx512( cv: *const u32, block: *const u8, block_len: u8, counter: u64, flags: u8, out: *mut u8, ); pub fn blake3_compress_in_place_avx512( cv: *mut u32, block: *const u8, block_len: u8, counter: u64, flags: u8, ); pub fn blake3_hash_many_avx512( inputs: *const *const u8, num_inputs: usize, blocks: usize, key: *const u32, counter: u64, increment_counter: bool, flags: u8, flags_start: u8, flags_end: u8, out: *mut u8, ); #[cfg(unix)] pub fn blake3_xof_many_avx512( cv: *const u32, block: *const u8, block_len: u8, counter: u64, flags: u8, out: *mut u8, outblocks: usize, ); } } #[cfg(feature = "neon")] pub mod neon { extern "C" { // NEON low level functions pub fn blake3_hash_many_neon( inputs: *const *const u8, num_inputs: usize, blocks: usize, key: *const u32, counter: u64, increment_counter: bool, flags: u8, flags_start: u8, flags_end: u8, out: *mut u8, ); } } } librecast/libs/blake3/c/blake3_c_rust_bindings/src/test.rs000066400000000000000000000524641502456746400241030ustar00rootroot00000000000000// Most of this code is duplicated from the root `blake3` crate. Perhaps we // could share more of it in the future. use crate::{BLOCK_LEN, CHUNK_LEN, OUT_LEN}; use arrayref::{array_mut_ref, array_ref}; use arrayvec::ArrayVec; use core::usize; use rand::prelude::*; const CHUNK_START: u8 = 1 << 0; const CHUNK_END: u8 = 1 << 1; const PARENT: u8 = 1 << 2; const ROOT: u8 = 1 << 3; const KEYED_HASH: u8 = 1 << 4; // const DERIVE_KEY_CONTEXT: u8 = 1 << 5; // const DERIVE_KEY_MATERIAL: u8 = 1 << 6; // Interesting input lengths to run tests on. pub const TEST_CASES: &[usize] = &[ 0, 1, 2, 3, 4, 5, 6, 7, 8, BLOCK_LEN - 1, BLOCK_LEN, BLOCK_LEN + 1, 2 * BLOCK_LEN - 1, 2 * BLOCK_LEN, 2 * BLOCK_LEN + 1, CHUNK_LEN - 1, CHUNK_LEN, CHUNK_LEN + 1, 2 * CHUNK_LEN, 2 * CHUNK_LEN + 1, 3 * CHUNK_LEN, 3 * CHUNK_LEN + 1, 4 * CHUNK_LEN, 4 * CHUNK_LEN + 1, 5 * CHUNK_LEN, 5 * CHUNK_LEN + 1, 6 * CHUNK_LEN, 6 * CHUNK_LEN + 1, 7 * CHUNK_LEN, 7 * CHUNK_LEN + 1, 8 * CHUNK_LEN, 8 * CHUNK_LEN + 1, 16 * CHUNK_LEN, // AVX512's bandwidth 31 * CHUNK_LEN, // 16 + 8 + 4 + 2 + 1 100 * CHUNK_LEN, // subtrees larger than MAX_SIMD_DEGREE chunks ]; pub const TEST_CASES_MAX: usize = 100 * CHUNK_LEN; // There's a test to make sure these two are equal below. pub const TEST_KEY: [u8; 32] = *b"whats the Elvish word for friend"; pub const TEST_KEY_WORDS: [u32; 8] = [ 1952540791, 1752440947, 1816469605, 1752394102, 1919907616, 1868963940, 1919295602, 1684956521, ]; // Paint the input with a repeating byte pattern. We use a cycle length of 251, // because that's the largest prime number less than 256. This makes it // unlikely to swapping any two adjacent input blocks or chunks will give the // same answer. fn paint_test_input(buf: &mut [u8]) { for (i, b) in buf.iter_mut().enumerate() { *b = (i % 251) as u8; } } #[inline(always)] fn le_bytes_from_words_32(words: &[u32; 8]) -> [u8; 32] { let mut out = [0; 32]; *array_mut_ref!(out, 0 * 4, 4) = words[0].to_le_bytes(); *array_mut_ref!(out, 1 * 4, 4) = words[1].to_le_bytes(); *array_mut_ref!(out, 2 * 4, 4) = words[2].to_le_bytes(); *array_mut_ref!(out, 3 * 4, 4) = words[3].to_le_bytes(); *array_mut_ref!(out, 4 * 4, 4) = words[4].to_le_bytes(); *array_mut_ref!(out, 5 * 4, 4) = words[5].to_le_bytes(); *array_mut_ref!(out, 6 * 4, 4) = words[6].to_le_bytes(); *array_mut_ref!(out, 7 * 4, 4) = words[7].to_le_bytes(); out } type CompressInPlaceFn = unsafe extern "C" fn(cv: *mut u32, block: *const u8, block_len: u8, counter: u64, flags: u8); type CompressXofFn = unsafe extern "C" fn( cv: *const u32, block: *const u8, block_len: u8, counter: u64, flags: u8, out: *mut u8, ); // A shared helper function for platform-specific tests. pub fn test_compress_fn(compress_in_place_fn: CompressInPlaceFn, compress_xof_fn: CompressXofFn) { let initial_state = TEST_KEY_WORDS; let block_len: u8 = 61; let mut block = [0; BLOCK_LEN]; paint_test_input(&mut block[..block_len as usize]); // Use a counter with set bits in both 32-bit words. let counter = (5u64 << 32) + 6; let flags = CHUNK_END | ROOT | KEYED_HASH; let mut portable_out = [0; 64]; unsafe { crate::ffi::blake3_compress_xof_portable( initial_state.as_ptr(), block.as_ptr(), block_len, counter, flags, portable_out.as_mut_ptr(), ); } let mut test_state = initial_state; unsafe { compress_in_place_fn( test_state.as_mut_ptr(), block.as_ptr(), block_len, counter, flags, ) }; let test_state_bytes = le_bytes_from_words_32(&test_state); let mut test_xof = [0; 64]; unsafe { compress_xof_fn( initial_state.as_ptr(), block.as_ptr(), block_len, counter, flags, test_xof.as_mut_ptr(), ) }; assert_eq!(&portable_out[..32], &test_state_bytes[..]); assert_eq!(&portable_out[..], &test_xof[..]); } // Testing the portable implementation against itself is circular, but why not. #[test] fn test_compress_portable() { test_compress_fn( crate::ffi::blake3_compress_in_place_portable, crate::ffi::blake3_compress_xof_portable, ); } #[test] #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] fn test_compress_sse2() { if !crate::sse2_detected() { return; } test_compress_fn( crate::ffi::x86::blake3_compress_in_place_sse2, crate::ffi::x86::blake3_compress_xof_sse2, ); } #[test] #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] fn test_compress_sse41() { if !crate::sse41_detected() { return; } test_compress_fn( crate::ffi::x86::blake3_compress_in_place_sse41, crate::ffi::x86::blake3_compress_xof_sse41, ); } #[test] #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] fn test_compress_avx512() { if !crate::avx512_detected() { return; } test_compress_fn( crate::ffi::x86::blake3_compress_in_place_avx512, crate::ffi::x86::blake3_compress_xof_avx512, ); } type HashManyFn = unsafe extern "C" fn( inputs: *const *const u8, num_inputs: usize, blocks: usize, key: *const u32, counter: u64, increment_counter: bool, flags: u8, flags_start: u8, flags_end: u8, out: *mut u8, ); // A shared helper function for platform-specific tests. pub fn test_hash_many_fn(hash_many_fn: HashManyFn) { // Test a few different initial counter values. // - 0: The base case. // - u32::MAX: The low word of the counter overflows for all inputs except the first. // - i32::MAX: *No* overflow. But carry bugs in tricky SIMD code can screw this up, if you XOR // when you're supposed to ANDNOT... let initial_counters = [0, u32::MAX as u64, i32::MAX as u64]; for counter in initial_counters { dbg!(counter); // 31 (16 + 8 + 4 + 2 + 1) inputs const NUM_INPUTS: usize = 31; let mut input_buf = [0; CHUNK_LEN * NUM_INPUTS]; crate::test::paint_test_input(&mut input_buf); // First hash chunks. let mut chunks = ArrayVec::<&[u8; CHUNK_LEN], NUM_INPUTS>::new(); for i in 0..NUM_INPUTS { chunks.push(array_ref!(input_buf, i * CHUNK_LEN, CHUNK_LEN)); } let mut portable_chunks_out = [0; NUM_INPUTS * OUT_LEN]; unsafe { crate::ffi::blake3_hash_many_portable( chunks.as_ptr() as _, chunks.len(), CHUNK_LEN / BLOCK_LEN, TEST_KEY_WORDS.as_ptr(), counter, true, KEYED_HASH, CHUNK_START, CHUNK_END, portable_chunks_out.as_mut_ptr(), ); } let mut test_chunks_out = [0; NUM_INPUTS * OUT_LEN]; unsafe { hash_many_fn( chunks.as_ptr() as _, chunks.len(), CHUNK_LEN / BLOCK_LEN, TEST_KEY_WORDS.as_ptr(), counter, true, KEYED_HASH, CHUNK_START, CHUNK_END, test_chunks_out.as_mut_ptr(), ); } for n in 0..NUM_INPUTS { dbg!(n); assert_eq!( &portable_chunks_out[n * OUT_LEN..][..OUT_LEN], &test_chunks_out[n * OUT_LEN..][..OUT_LEN] ); } // Then hash parents. let mut parents = ArrayVec::<&[u8; 2 * OUT_LEN], NUM_INPUTS>::new(); for i in 0..NUM_INPUTS { parents.push(array_ref!(input_buf, i * 2 * OUT_LEN, 2 * OUT_LEN)); } let mut portable_parents_out = [0; NUM_INPUTS * OUT_LEN]; unsafe { crate::ffi::blake3_hash_many_portable( parents.as_ptr() as _, parents.len(), 1, TEST_KEY_WORDS.as_ptr(), counter, false, KEYED_HASH | PARENT, 0, 0, portable_parents_out.as_mut_ptr(), ); } let mut test_parents_out = [0; NUM_INPUTS * OUT_LEN]; unsafe { hash_many_fn( parents.as_ptr() as _, parents.len(), 1, TEST_KEY_WORDS.as_ptr(), counter, false, KEYED_HASH | PARENT, 0, 0, test_parents_out.as_mut_ptr(), ); } for n in 0..NUM_INPUTS { dbg!(n); assert_eq!( &portable_parents_out[n * OUT_LEN..][..OUT_LEN], &test_parents_out[n * OUT_LEN..][..OUT_LEN] ); } } } // Testing the portable implementation against itself is circular, but why not. #[test] fn test_hash_many_portable() { test_hash_many_fn(crate::ffi::blake3_hash_many_portable); } #[test] #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] fn test_hash_many_sse2() { if !crate::sse2_detected() { return; } test_hash_many_fn(crate::ffi::x86::blake3_hash_many_sse2); } #[test] #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] fn test_hash_many_sse41() { if !crate::sse41_detected() { return; } test_hash_many_fn(crate::ffi::x86::blake3_hash_many_sse41); } #[test] #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] fn test_hash_many_avx2() { if !crate::avx2_detected() { return; } test_hash_many_fn(crate::ffi::x86::blake3_hash_many_avx2); } #[test] #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] fn test_hash_many_avx512() { if !crate::avx512_detected() { return; } test_hash_many_fn(crate::ffi::x86::blake3_hash_many_avx512); } #[test] #[cfg(feature = "neon")] fn test_hash_many_neon() { test_hash_many_fn(crate::ffi::neon::blake3_hash_many_neon); } #[allow(unused)] type XofManyFunction = unsafe extern "C" fn( cv: *const u32, block: *const u8, block_len: u8, counter: u64, flags: u8, out: *mut u8, outblocks: usize, ); // A shared helper function for platform-specific tests. #[allow(unused)] pub fn test_xof_many_fn(xof_many_function: XofManyFunction) { let mut block = [0; BLOCK_LEN]; let block_len = 42; crate::test::paint_test_input(&mut block[..block_len]); let cv = [40, 41, 42, 43, 44, 45, 46, 47]; let flags = KEYED_HASH; // Test a few different initial counter values. // - 0: The base case. // - u32::MAX: The low word of the counter overflows for all inputs except the first. // - i32::MAX: *No* overflow. But carry bugs in tricky SIMD code can screw this up, if you XOR // when you're supposed to ANDNOT... let initial_counters = [0, u32::MAX as u64, i32::MAX as u64]; for counter in initial_counters { dbg!(counter); // 31 (16 + 8 + 4 + 2 + 1) outputs const OUTPUT_SIZE: usize = 31 * BLOCK_LEN; let mut portable_out = [0u8; OUTPUT_SIZE]; for (i, out_block) in portable_out.chunks_exact_mut(BLOCK_LEN).enumerate() { unsafe { crate::ffi::blake3_compress_xof_portable( cv.as_ptr(), block.as_ptr(), block_len as u8, counter + i as u64, flags, out_block.as_mut_ptr(), ); } } let mut test_out = [0u8; OUTPUT_SIZE]; unsafe { xof_many_function( cv.as_ptr(), block.as_ptr(), block_len as u8, counter, flags, test_out.as_mut_ptr(), OUTPUT_SIZE / BLOCK_LEN, ); } assert_eq!(portable_out, test_out); } // Test that xof_many doesn't write more blocks than requested. Note that the current assembly // implementation always outputs at least one block, so we don't test the zero case. for block_count in 1..=32 { let mut array = [0; BLOCK_LEN * 33]; let output_start = 17; let output_len = block_count * BLOCK_LEN; let output_end = output_start + output_len; let output = &mut array[output_start..output_end]; unsafe { xof_many_function( cv.as_ptr(), block.as_ptr(), block_len as u8, 0, flags, output.as_mut_ptr(), block_count, ); } for i in 0..array.len() { if i < output_start || output_end <= i { assert_eq!(0, array[i], "index {i}"); } } } } #[test] #[cfg(unix)] #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] fn test_xof_many_avx512() { if !crate::avx512_detected() { return; } test_xof_many_fn(crate::ffi::x86::blake3_xof_many_avx512); } #[test] fn test_compare_reference_impl() { const OUT: usize = 303; // more than 64, not a multiple of 4 let mut input_buf = [0; TEST_CASES_MAX]; paint_test_input(&mut input_buf); for &case in TEST_CASES { let input = &input_buf[..case]; dbg!(case); // regular { let mut reference_hasher = reference_impl::Hasher::new(); reference_hasher.update(input); let mut expected_out = [0; OUT]; reference_hasher.finalize(&mut expected_out); let mut test_hasher = crate::Hasher::new(); test_hasher.update(input); let mut test_out = [0; OUT]; test_hasher.finalize(&mut test_out); assert_eq!(test_out[..], expected_out[..]); #[cfg(feature = "tbb")] { let mut tbb_hasher = crate::Hasher::new(); tbb_hasher.update_tbb(input); let mut tbb_out = [0; OUT]; tbb_hasher.finalize(&mut tbb_out); assert_eq!(tbb_out[..], expected_out[..]); } } // keyed { let mut reference_hasher = reference_impl::Hasher::new_keyed(&TEST_KEY); reference_hasher.update(input); let mut expected_out = [0; OUT]; reference_hasher.finalize(&mut expected_out); let mut test_hasher = crate::Hasher::new_keyed(&TEST_KEY); test_hasher.update(input); let mut test_out = [0; OUT]; test_hasher.finalize(&mut test_out); assert_eq!(test_out[..], expected_out[..]); #[cfg(feature = "tbb")] { let mut tbb_hasher = crate::Hasher::new_keyed(&TEST_KEY); tbb_hasher.update_tbb(input); let mut tbb_out = [0; OUT]; tbb_hasher.finalize(&mut tbb_out); assert_eq!(tbb_out[..], expected_out[..]); } } // derive_key { let context = "BLAKE3 2019-12-27 16:13:59 example context (not the test vector one)"; let mut reference_hasher = reference_impl::Hasher::new_derive_key(context); reference_hasher.update(input); let mut expected_out = [0; OUT]; reference_hasher.finalize(&mut expected_out); // the regular C string API let mut test_hasher = crate::Hasher::new_derive_key(context); test_hasher.update(input); let mut test_out = [0; OUT]; test_hasher.finalize(&mut test_out); assert_eq!(test_out[..], expected_out[..]); // the raw bytes API let mut test_hasher_raw = crate::Hasher::new_derive_key_raw(context.as_bytes()); test_hasher_raw.update(input); let mut test_out_raw = [0; OUT]; test_hasher_raw.finalize(&mut test_out_raw); assert_eq!(test_out_raw[..], expected_out[..]); #[cfg(feature = "tbb")] { let mut tbb_hasher = crate::Hasher::new_derive_key(context); tbb_hasher.update_tbb(input); let mut tbb_out = [0; OUT]; tbb_hasher.finalize(&mut tbb_out); assert_eq!(tbb_out[..], expected_out[..]); } } } } fn reference_hash(input: &[u8]) -> [u8; OUT_LEN] { let mut hasher = reference_impl::Hasher::new(); hasher.update(input); let mut bytes = [0; OUT_LEN]; hasher.finalize(&mut bytes); bytes.into() } #[test] fn test_compare_update_multiple() { // Don't use all the long test cases here, since that's unnecessarily slow // in debug mode. let mut short_test_cases = TEST_CASES; while *short_test_cases.last().unwrap() > 4 * CHUNK_LEN { short_test_cases = &short_test_cases[..short_test_cases.len() - 1]; } assert_eq!(*short_test_cases.last().unwrap(), 4 * CHUNK_LEN); let mut input_buf = [0; 2 * TEST_CASES_MAX]; paint_test_input(&mut input_buf); for &first_update in short_test_cases { dbg!(first_update); let first_input = &input_buf[..first_update]; let mut test_hasher = crate::Hasher::new(); test_hasher.update(first_input); for &second_update in short_test_cases { dbg!(second_update); let second_input = &input_buf[first_update..][..second_update]; let total_input = &input_buf[..first_update + second_update]; // Clone the hasher with first_update bytes already written, so // that the next iteration can reuse it. let mut test_hasher = test_hasher.clone(); test_hasher.update(second_input); let mut test_out = [0; OUT_LEN]; test_hasher.finalize(&mut test_out); let expected = reference_hash(total_input); assert_eq!(expected, test_out); } } } #[test] fn test_fuzz_hasher() { const INPUT_MAX: usize = 4 * CHUNK_LEN; let mut input_buf = [0; 3 * INPUT_MAX]; paint_test_input(&mut input_buf); // Don't do too many iterations in debug mode, to keep the tests under a // second or so. CI should run tests in release mode also. Provide an // environment variable for specifying a larger number of fuzz iterations. let num_tests = if cfg!(debug_assertions) { 100 } else { 10_000 }; // Use a fixed RNG seed for reproducibility. let mut rng = rand_chacha::ChaCha8Rng::from_seed([1; 32]); for _num_test in 0..num_tests { dbg!(_num_test); let mut hasher = crate::Hasher::new(); let mut total_input = 0; // For each test, write 3 inputs of random length. for _ in 0..3 { let input_len = rng.random_range(0..INPUT_MAX + 1); dbg!(input_len); let input = &input_buf[total_input..][..input_len]; hasher.update(input); total_input += input_len; } let expected = reference_hash(&input_buf[..total_input]); let mut test_out = [0; 32]; hasher.finalize(&mut test_out); assert_eq!(expected, test_out); } } #[test] fn test_finalize_seek() { let mut expected = [0; 1000]; { let mut reference_hasher = reference_impl::Hasher::new(); reference_hasher.update(b"foobarbaz"); reference_hasher.finalize(&mut expected); } let mut test_hasher = crate::Hasher::new(); test_hasher.update(b"foobarbaz"); let mut out = [0; 103]; for &seek in &[0, 1, 7, 59, 63, 64, 65, 501, expected.len() - out.len()] { dbg!(seek); test_hasher.finalize_seek(seek as u64, &mut out); assert_eq!(&expected[seek..][..out.len()], &out[..]); } } #[test] fn test_reset() { { let mut hasher = crate::Hasher::new(); hasher.update(&[42; 3 * CHUNK_LEN + 7]); hasher.reset(); hasher.update(&[42; CHUNK_LEN + 3]); let mut output = [0; 32]; hasher.finalize(&mut output); let mut reference_hasher = reference_impl::Hasher::new(); reference_hasher.update(&[42; CHUNK_LEN + 3]); let mut reference_hash = [0; 32]; reference_hasher.finalize(&mut reference_hash); assert_eq!(reference_hash, output); } { let key = &[99; 32]; let mut hasher = crate::Hasher::new_keyed(key); hasher.update(&[42; 3 * CHUNK_LEN + 7]); hasher.reset(); hasher.update(&[42; CHUNK_LEN + 3]); let mut output = [0; 32]; hasher.finalize(&mut output); let mut reference_hasher = reference_impl::Hasher::new_keyed(key); reference_hasher.update(&[42; CHUNK_LEN + 3]); let mut reference_hash = [0; 32]; reference_hasher.finalize(&mut reference_hash); assert_eq!(reference_hash, output); } { let context = "BLAKE3 2020-02-12 10:20:58 reset test"; let mut hasher = crate::Hasher::new_derive_key(context); hasher.update(&[42; 3 * CHUNK_LEN + 7]); hasher.reset(); hasher.update(&[42; CHUNK_LEN + 3]); let mut output = [0; 32]; hasher.finalize(&mut output); let mut reference_hasher = reference_impl::Hasher::new_derive_key(context); reference_hasher.update(&[42; CHUNK_LEN + 3]); let mut reference_hash = [0; 32]; reference_hasher.finalize(&mut reference_hash); assert_eq!(reference_hash, output); } } librecast/libs/blake3/c/blake3_dispatch.c000066400000000000000000000217151502456746400205510ustar00rootroot00000000000000#include #include #include #include "blake3_impl.h" #if defined(_MSC_VER) #include #endif #if defined(IS_X86) #if defined(_MSC_VER) #include #elif defined(__GNUC__) #include #else #undef IS_X86 /* Unimplemented! */ #endif #endif #if !defined(BLAKE3_ATOMICS) #if defined(__has_include) #if __has_include() && !defined(_MSC_VER) #define BLAKE3_ATOMICS 1 #else #define BLAKE3_ATOMICS 0 #endif /* __has_include() && !defined(_MSC_VER) */ #else #define BLAKE3_ATOMICS 0 #endif /* defined(__has_include) */ #endif /* BLAKE3_ATOMICS */ #if BLAKE3_ATOMICS #define ATOMIC_INT _Atomic int #define ATOMIC_LOAD(x) x #define ATOMIC_STORE(x, y) x = y #elif defined(_MSC_VER) #define ATOMIC_INT LONG #define ATOMIC_LOAD(x) InterlockedOr(&x, 0) #define ATOMIC_STORE(x, y) InterlockedExchange(&x, y) #else #define ATOMIC_INT int #define ATOMIC_LOAD(x) x #define ATOMIC_STORE(x, y) x = y #endif #define MAYBE_UNUSED(x) (void)((x)) #if defined(IS_X86) static uint64_t xgetbv(void) { #if defined(_MSC_VER) return _xgetbv(0); #else uint32_t eax = 0, edx = 0; __asm__ __volatile__("xgetbv\n" : "=a"(eax), "=d"(edx) : "c"(0)); return ((uint64_t)edx << 32) | eax; #endif } static void cpuid(uint32_t out[4], uint32_t id) { #if defined(_MSC_VER) __cpuid((int *)out, id); #elif defined(__i386__) || defined(_M_IX86) __asm__ __volatile__("movl %%ebx, %1\n" "cpuid\n" "xchgl %1, %%ebx\n" : "=a"(out[0]), "=r"(out[1]), "=c"(out[2]), "=d"(out[3]) : "a"(id)); #else __asm__ __volatile__("cpuid\n" : "=a"(out[0]), "=b"(out[1]), "=c"(out[2]), "=d"(out[3]) : "a"(id)); #endif } static void cpuidex(uint32_t out[4], uint32_t id, uint32_t sid) { #if defined(_MSC_VER) __cpuidex((int *)out, id, sid); #elif defined(__i386__) || defined(_M_IX86) __asm__ __volatile__("movl %%ebx, %1\n" "cpuid\n" "xchgl %1, %%ebx\n" : "=a"(out[0]), "=r"(out[1]), "=c"(out[2]), "=d"(out[3]) : "a"(id), "c"(sid)); #else __asm__ __volatile__("cpuid\n" : "=a"(out[0]), "=b"(out[1]), "=c"(out[2]), "=d"(out[3]) : "a"(id), "c"(sid)); #endif } #endif enum cpu_feature { SSE2 = 1 << 0, SSSE3 = 1 << 1, SSE41 = 1 << 2, AVX = 1 << 3, AVX2 = 1 << 4, AVX512F = 1 << 5, AVX512VL = 1 << 6, /* ... */ UNDEFINED = 1 << 30 }; #if !defined(BLAKE3_TESTING) static /* Allow the variable to be controlled manually for testing */ #endif ATOMIC_INT g_cpu_features = UNDEFINED; #if !defined(BLAKE3_TESTING) static #endif enum cpu_feature get_cpu_features(void) { /* If TSAN detects a data race here, try compiling with -DBLAKE3_ATOMICS=1 */ enum cpu_feature features = ATOMIC_LOAD(g_cpu_features); if (features != UNDEFINED) { return features; } else { #if defined(IS_X86) uint32_t regs[4] = {0}; uint32_t *eax = ®s[0], *ebx = ®s[1], *ecx = ®s[2], *edx = ®s[3]; (void)edx; features = 0; cpuid(regs, 0); const int max_id = *eax; cpuid(regs, 1); #if defined(__amd64__) || defined(_M_X64) features |= SSE2; #else if (*edx & (1UL << 26)) features |= SSE2; #endif if (*ecx & (1UL << 9)) features |= SSSE3; if (*ecx & (1UL << 19)) features |= SSE41; if (*ecx & (1UL << 27)) { // OSXSAVE const uint64_t mask = xgetbv(); if ((mask & 6) == 6) { // SSE and AVX states if (*ecx & (1UL << 28)) features |= AVX; if (max_id >= 7) { cpuidex(regs, 7, 0); if (*ebx & (1UL << 5)) features |= AVX2; if ((mask & 224) == 224) { // Opmask, ZMM_Hi256, Hi16_Zmm if (*ebx & (1UL << 31)) features |= AVX512VL; if (*ebx & (1UL << 16)) features |= AVX512F; } } } } ATOMIC_STORE(g_cpu_features, features); return features; #else /* How to detect NEON? */ return 0; #endif } } void blake3_compress_in_place(uint32_t cv[8], const uint8_t block[BLAKE3_BLOCK_LEN], uint8_t block_len, uint64_t counter, uint8_t flags) { #if defined(IS_X86) const enum cpu_feature features = get_cpu_features(); MAYBE_UNUSED(features); #if !defined(BLAKE3_NO_AVX512) if (features & AVX512VL) { blake3_compress_in_place_avx512(cv, block, block_len, counter, flags); return; } #endif #if !defined(BLAKE3_NO_SSE41) if (features & SSE41) { blake3_compress_in_place_sse41(cv, block, block_len, counter, flags); return; } #endif #if !defined(BLAKE3_NO_SSE2) if (features & SSE2) { blake3_compress_in_place_sse2(cv, block, block_len, counter, flags); return; } #endif #endif blake3_compress_in_place_portable(cv, block, block_len, counter, flags); } void blake3_compress_xof(const uint32_t cv[8], const uint8_t block[BLAKE3_BLOCK_LEN], uint8_t block_len, uint64_t counter, uint8_t flags, uint8_t out[64]) { #if defined(IS_X86) const enum cpu_feature features = get_cpu_features(); MAYBE_UNUSED(features); #if !defined(BLAKE3_NO_AVX512) if (features & AVX512VL) { blake3_compress_xof_avx512(cv, block, block_len, counter, flags, out); return; } #endif #if !defined(BLAKE3_NO_SSE41) if (features & SSE41) { blake3_compress_xof_sse41(cv, block, block_len, counter, flags, out); return; } #endif #if !defined(BLAKE3_NO_SSE2) if (features & SSE2) { blake3_compress_xof_sse2(cv, block, block_len, counter, flags, out); return; } #endif #endif blake3_compress_xof_portable(cv, block, block_len, counter, flags, out); } void blake3_xof_many(const uint32_t cv[8], const uint8_t block[BLAKE3_BLOCK_LEN], uint8_t block_len, uint64_t counter, uint8_t flags, uint8_t out[64], size_t outblocks) { if (outblocks == 0) { // The current assembly implementation always outputs at least 1 block. return; } #if defined(IS_X86) const enum cpu_feature features = get_cpu_features(); MAYBE_UNUSED(features); #if !defined(_WIN32) && !defined(BLAKE3_NO_AVX512) if (features & AVX512VL) { blake3_xof_many_avx512(cv, block, block_len, counter, flags, out, outblocks); return; } #endif #endif for(size_t i = 0; i < outblocks; ++i) { blake3_compress_xof(cv, block, block_len, counter + i, flags, out + 64*i); } } void blake3_hash_many(const uint8_t *const *inputs, size_t num_inputs, size_t blocks, const uint32_t key[8], uint64_t counter, bool increment_counter, uint8_t flags, uint8_t flags_start, uint8_t flags_end, uint8_t *out) { #if defined(IS_X86) const enum cpu_feature features = get_cpu_features(); MAYBE_UNUSED(features); #if !defined(BLAKE3_NO_AVX512) if ((features & (AVX512F|AVX512VL)) == (AVX512F|AVX512VL)) { blake3_hash_many_avx512(inputs, num_inputs, blocks, key, counter, increment_counter, flags, flags_start, flags_end, out); return; } #endif #if !defined(BLAKE3_NO_AVX2) if (features & AVX2) { blake3_hash_many_avx2(inputs, num_inputs, blocks, key, counter, increment_counter, flags, flags_start, flags_end, out); return; } #endif #if !defined(BLAKE3_NO_SSE41) if (features & SSE41) { blake3_hash_many_sse41(inputs, num_inputs, blocks, key, counter, increment_counter, flags, flags_start, flags_end, out); return; } #endif #if !defined(BLAKE3_NO_SSE2) if (features & SSE2) { blake3_hash_many_sse2(inputs, num_inputs, blocks, key, counter, increment_counter, flags, flags_start, flags_end, out); return; } #endif #endif #if BLAKE3_USE_NEON == 1 blake3_hash_many_neon(inputs, num_inputs, blocks, key, counter, increment_counter, flags, flags_start, flags_end, out); return; #endif blake3_hash_many_portable(inputs, num_inputs, blocks, key, counter, increment_counter, flags, flags_start, flags_end, out); } // The dynamically detected SIMD degree of the current platform. size_t blake3_simd_degree(void) { #if defined(IS_X86) const enum cpu_feature features = get_cpu_features(); MAYBE_UNUSED(features); #if !defined(BLAKE3_NO_AVX512) if ((features & (AVX512F|AVX512VL)) == (AVX512F|AVX512VL)) { return 16; } #endif #if !defined(BLAKE3_NO_AVX2) if (features & AVX2) { return 8; } #endif #if !defined(BLAKE3_NO_SSE41) if (features & SSE41) { return 4; } #endif #if !defined(BLAKE3_NO_SSE2) if (features & SSE2) { return 4; } #endif #endif #if BLAKE3_USE_NEON == 1 return 4; #endif return 1; } librecast/libs/blake3/c/blake3_impl.h000066400000000000000000000273761502456746400177310ustar00rootroot00000000000000#ifndef BLAKE3_IMPL_H #define BLAKE3_IMPL_H #include #include #include #include #include #include "blake3.h" #ifdef __cplusplus extern "C" { #endif // internal flags enum blake3_flags { CHUNK_START = 1 << 0, CHUNK_END = 1 << 1, PARENT = 1 << 2, ROOT = 1 << 3, KEYED_HASH = 1 << 4, DERIVE_KEY_CONTEXT = 1 << 5, DERIVE_KEY_MATERIAL = 1 << 6, }; // This C implementation tries to support recent versions of GCC, Clang, and // MSVC. #if defined(_MSC_VER) #define INLINE static __forceinline #else #define INLINE static inline __attribute__((always_inline)) #endif #ifdef __cplusplus #define NOEXCEPT noexcept #else #define NOEXCEPT #endif #if (defined(__x86_64__) || defined(_M_X64)) && !defined(_M_ARM64EC) #define IS_X86 #define IS_X86_64 #endif #if defined(__i386__) || defined(_M_IX86) #define IS_X86 #define IS_X86_32 #endif #if defined(__aarch64__) || defined(_M_ARM64) || defined(_M_ARM64EC) #define IS_AARCH64 #endif #if defined(IS_X86) #if defined(_MSC_VER) #include #endif #endif #if !defined(BLAKE3_USE_NEON) // If BLAKE3_USE_NEON not manually set, autodetect based on AArch64ness #if defined(IS_AARCH64) #if defined(__ARM_BIG_ENDIAN) #define BLAKE3_USE_NEON 0 #else #define BLAKE3_USE_NEON 1 #endif #else #define BLAKE3_USE_NEON 0 #endif #endif #if defined(IS_X86) #define MAX_SIMD_DEGREE 16 #elif BLAKE3_USE_NEON == 1 #define MAX_SIMD_DEGREE 4 #else #define MAX_SIMD_DEGREE 1 #endif // There are some places where we want a static size that's equal to the // MAX_SIMD_DEGREE, but also at least 2. #define MAX_SIMD_DEGREE_OR_2 (MAX_SIMD_DEGREE > 2 ? MAX_SIMD_DEGREE : 2) static const uint32_t IV[8] = {0x6A09E667UL, 0xBB67AE85UL, 0x3C6EF372UL, 0xA54FF53AUL, 0x510E527FUL, 0x9B05688CUL, 0x1F83D9ABUL, 0x5BE0CD19UL}; static const uint8_t MSG_SCHEDULE[7][16] = { {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}, {2, 6, 3, 10, 7, 0, 4, 13, 1, 11, 12, 5, 9, 14, 15, 8}, {3, 4, 10, 12, 13, 2, 7, 14, 6, 5, 9, 0, 11, 15, 8, 1}, {10, 7, 12, 9, 14, 3, 13, 15, 4, 0, 11, 2, 5, 8, 1, 6}, {12, 13, 9, 11, 15, 10, 14, 8, 7, 2, 5, 3, 0, 1, 6, 4}, {9, 14, 11, 5, 8, 12, 15, 1, 13, 3, 0, 10, 2, 6, 4, 7}, {11, 15, 5, 0, 1, 9, 8, 6, 14, 10, 2, 12, 3, 4, 7, 13}, }; /* Find index of the highest set bit */ /* x is assumed to be nonzero. */ static unsigned int highest_one(uint64_t x) { #if defined(__GNUC__) || defined(__clang__) return 63 ^ (unsigned int)__builtin_clzll(x); #elif defined(_MSC_VER) && defined(IS_X86_64) unsigned long index; _BitScanReverse64(&index, x); return index; #elif defined(_MSC_VER) && defined(IS_X86_32) if(x >> 32) { unsigned long index; _BitScanReverse(&index, (unsigned long)(x >> 32)); return 32 + index; } else { unsigned long index; _BitScanReverse(&index, (unsigned long)x); return index; } #else unsigned int c = 0; if(x & 0xffffffff00000000ULL) { x >>= 32; c += 32; } if(x & 0x00000000ffff0000ULL) { x >>= 16; c += 16; } if(x & 0x000000000000ff00ULL) { x >>= 8; c += 8; } if(x & 0x00000000000000f0ULL) { x >>= 4; c += 4; } if(x & 0x000000000000000cULL) { x >>= 2; c += 2; } if(x & 0x0000000000000002ULL) { c += 1; } return c; #endif } // Count the number of 1 bits. INLINE unsigned int popcnt(uint64_t x) { #if defined(__GNUC__) || defined(__clang__) return (unsigned int)__builtin_popcountll(x); #else unsigned int count = 0; while (x != 0) { count += 1; x &= x - 1; } return count; #endif } // Largest power of two less than or equal to x. As a special case, returns 1 // when x is 0. INLINE uint64_t round_down_to_power_of_2(uint64_t x) { return 1ULL << highest_one(x | 1); } INLINE uint32_t counter_low(uint64_t counter) { return (uint32_t)counter; } INLINE uint32_t counter_high(uint64_t counter) { return (uint32_t)(counter >> 32); } INLINE uint32_t load32(const void *src) { const uint8_t *p = (const uint8_t *)src; return ((uint32_t)(p[0]) << 0) | ((uint32_t)(p[1]) << 8) | ((uint32_t)(p[2]) << 16) | ((uint32_t)(p[3]) << 24); } INLINE void load_key_words(const uint8_t key[BLAKE3_KEY_LEN], uint32_t key_words[8]) { key_words[0] = load32(&key[0 * 4]); key_words[1] = load32(&key[1 * 4]); key_words[2] = load32(&key[2 * 4]); key_words[3] = load32(&key[3 * 4]); key_words[4] = load32(&key[4 * 4]); key_words[5] = load32(&key[5 * 4]); key_words[6] = load32(&key[6 * 4]); key_words[7] = load32(&key[7 * 4]); } INLINE void load_block_words(const uint8_t block[BLAKE3_BLOCK_LEN], uint32_t block_words[16]) { for (size_t i = 0; i < 16; i++) { block_words[i] = load32(&block[i * 4]); } } INLINE void store32(void *dst, uint32_t w) { uint8_t *p = (uint8_t *)dst; p[0] = (uint8_t)(w >> 0); p[1] = (uint8_t)(w >> 8); p[2] = (uint8_t)(w >> 16); p[3] = (uint8_t)(w >> 24); } INLINE void store_cv_words(uint8_t bytes_out[32], uint32_t cv_words[8]) { store32(&bytes_out[0 * 4], cv_words[0]); store32(&bytes_out[1 * 4], cv_words[1]); store32(&bytes_out[2 * 4], cv_words[2]); store32(&bytes_out[3 * 4], cv_words[3]); store32(&bytes_out[4 * 4], cv_words[4]); store32(&bytes_out[5 * 4], cv_words[5]); store32(&bytes_out[6 * 4], cv_words[6]); store32(&bytes_out[7 * 4], cv_words[7]); } void blake3_compress_in_place(uint32_t cv[8], const uint8_t block[BLAKE3_BLOCK_LEN], uint8_t block_len, uint64_t counter, uint8_t flags); void blake3_compress_xof(const uint32_t cv[8], const uint8_t block[BLAKE3_BLOCK_LEN], uint8_t block_len, uint64_t counter, uint8_t flags, uint8_t out[64]); void blake3_xof_many(const uint32_t cv[8], const uint8_t block[BLAKE3_BLOCK_LEN], uint8_t block_len, uint64_t counter, uint8_t flags, uint8_t out[64], size_t outblocks); void blake3_hash_many(const uint8_t *const *inputs, size_t num_inputs, size_t blocks, const uint32_t key[8], uint64_t counter, bool increment_counter, uint8_t flags, uint8_t flags_start, uint8_t flags_end, uint8_t *out); size_t blake3_simd_degree(void); BLAKE3_PRIVATE size_t blake3_compress_subtree_wide(const uint8_t *input, size_t input_len, const uint32_t key[8], uint64_t chunk_counter, uint8_t flags, uint8_t *out, bool use_tbb); #if defined(BLAKE3_USE_TBB) BLAKE3_PRIVATE void blake3_compress_subtree_wide_join_tbb( // shared params const uint32_t key[8], uint8_t flags, bool use_tbb, // left-hand side params const uint8_t *l_input, size_t l_input_len, uint64_t l_chunk_counter, uint8_t *l_cvs, size_t *l_n, // right-hand side params const uint8_t *r_input, size_t r_input_len, uint64_t r_chunk_counter, uint8_t *r_cvs, size_t *r_n) NOEXCEPT; #endif // Declarations for implementation-specific functions. void blake3_compress_in_place_portable(uint32_t cv[8], const uint8_t block[BLAKE3_BLOCK_LEN], uint8_t block_len, uint64_t counter, uint8_t flags); void blake3_compress_xof_portable(const uint32_t cv[8], const uint8_t block[BLAKE3_BLOCK_LEN], uint8_t block_len, uint64_t counter, uint8_t flags, uint8_t out[64]); void blake3_hash_many_portable(const uint8_t *const *inputs, size_t num_inputs, size_t blocks, const uint32_t key[8], uint64_t counter, bool increment_counter, uint8_t flags, uint8_t flags_start, uint8_t flags_end, uint8_t *out); #if defined(IS_X86) #if !defined(BLAKE3_NO_SSE2) void blake3_compress_in_place_sse2(uint32_t cv[8], const uint8_t block[BLAKE3_BLOCK_LEN], uint8_t block_len, uint64_t counter, uint8_t flags); void blake3_compress_xof_sse2(const uint32_t cv[8], const uint8_t block[BLAKE3_BLOCK_LEN], uint8_t block_len, uint64_t counter, uint8_t flags, uint8_t out[64]); void blake3_hash_many_sse2(const uint8_t *const *inputs, size_t num_inputs, size_t blocks, const uint32_t key[8], uint64_t counter, bool increment_counter, uint8_t flags, uint8_t flags_start, uint8_t flags_end, uint8_t *out); #endif #if !defined(BLAKE3_NO_SSE41) void blake3_compress_in_place_sse41(uint32_t cv[8], const uint8_t block[BLAKE3_BLOCK_LEN], uint8_t block_len, uint64_t counter, uint8_t flags); void blake3_compress_xof_sse41(const uint32_t cv[8], const uint8_t block[BLAKE3_BLOCK_LEN], uint8_t block_len, uint64_t counter, uint8_t flags, uint8_t out[64]); void blake3_hash_many_sse41(const uint8_t *const *inputs, size_t num_inputs, size_t blocks, const uint32_t key[8], uint64_t counter, bool increment_counter, uint8_t flags, uint8_t flags_start, uint8_t flags_end, uint8_t *out); #endif #if !defined(BLAKE3_NO_AVX2) void blake3_hash_many_avx2(const uint8_t *const *inputs, size_t num_inputs, size_t blocks, const uint32_t key[8], uint64_t counter, bool increment_counter, uint8_t flags, uint8_t flags_start, uint8_t flags_end, uint8_t *out); #endif #if !defined(BLAKE3_NO_AVX512) void blake3_compress_in_place_avx512(uint32_t cv[8], const uint8_t block[BLAKE3_BLOCK_LEN], uint8_t block_len, uint64_t counter, uint8_t flags); void blake3_compress_xof_avx512(const uint32_t cv[8], const uint8_t block[BLAKE3_BLOCK_LEN], uint8_t block_len, uint64_t counter, uint8_t flags, uint8_t out[64]); void blake3_hash_many_avx512(const uint8_t *const *inputs, size_t num_inputs, size_t blocks, const uint32_t key[8], uint64_t counter, bool increment_counter, uint8_t flags, uint8_t flags_start, uint8_t flags_end, uint8_t *out); #if !defined(_WIN32) void blake3_xof_many_avx512(const uint32_t cv[8], const uint8_t block[BLAKE3_BLOCK_LEN], uint8_t block_len, uint64_t counter, uint8_t flags, uint8_t* out, size_t outblocks); #endif #endif #endif #if BLAKE3_USE_NEON == 1 void blake3_hash_many_neon(const uint8_t *const *inputs, size_t num_inputs, size_t blocks, const uint32_t key[8], uint64_t counter, bool increment_counter, uint8_t flags, uint8_t flags_start, uint8_t flags_end, uint8_t *out); #endif #ifdef __cplusplus } #endif #endif /* BLAKE3_IMPL_H */ librecast/libs/blake3/c/blake3_neon.c000066400000000000000000000330111502456746400177010ustar00rootroot00000000000000#include "blake3_impl.h" #include #ifdef __ARM_BIG_ENDIAN #error "This implementation only supports little-endian ARM." // It might be that all we need for big-endian support here is to get the loads // and stores right, but step zero would be finding a way to test it in CI. #endif INLINE uint32x4_t loadu_128(const uint8_t src[16]) { // vld1q_u32 has alignment requirements. Don't use it. return vreinterpretq_u32_u8(vld1q_u8(src)); } INLINE void storeu_128(uint32x4_t src, uint8_t dest[16]) { // vst1q_u32 has alignment requirements. Don't use it. vst1q_u8(dest, vreinterpretq_u8_u32(src)); } INLINE uint32x4_t add_128(uint32x4_t a, uint32x4_t b) { return vaddq_u32(a, b); } INLINE uint32x4_t xor_128(uint32x4_t a, uint32x4_t b) { return veorq_u32(a, b); } INLINE uint32x4_t set1_128(uint32_t x) { return vld1q_dup_u32(&x); } INLINE uint32x4_t set4(uint32_t a, uint32_t b, uint32_t c, uint32_t d) { uint32_t array[4] = {a, b, c, d}; return vld1q_u32(array); } INLINE uint32x4_t rot16_128(uint32x4_t x) { // The straightforward implementation would be two shifts and an or, but that's // slower on microarchitectures we've tested. See // https://github.com/BLAKE3-team/BLAKE3/pull/319. // return vorrq_u32(vshrq_n_u32(x, 16), vshlq_n_u32(x, 32 - 16)); return vreinterpretq_u32_u16(vrev32q_u16(vreinterpretq_u16_u32(x))); } INLINE uint32x4_t rot12_128(uint32x4_t x) { // See comment in rot16_128. // return vorrq_u32(vshrq_n_u32(x, 12), vshlq_n_u32(x, 32 - 12)); return vsriq_n_u32(vshlq_n_u32(x, 32-12), x, 12); } INLINE uint32x4_t rot8_128(uint32x4_t x) { // See comment in rot16_128. // return vorrq_u32(vshrq_n_u32(x, 8), vshlq_n_u32(x, 32 - 8)); #if defined(__clang__) return vreinterpretq_u32_u8(__builtin_shufflevector(vreinterpretq_u8_u32(x), vreinterpretq_u8_u32(x), 1,2,3,0,5,6,7,4,9,10,11,8,13,14,15,12)); #elif __GNUC__ * 10000 + __GNUC_MINOR__ * 100 >=40700 static const uint8x16_t r8 = {1,2,3,0,5,6,7,4,9,10,11,8,13,14,15,12}; return vreinterpretq_u32_u8(__builtin_shuffle(vreinterpretq_u8_u32(x), vreinterpretq_u8_u32(x), r8)); #else return vsriq_n_u32(vshlq_n_u32(x, 32-8), x, 8); #endif } INLINE uint32x4_t rot7_128(uint32x4_t x) { // See comment in rot16_128. // return vorrq_u32(vshrq_n_u32(x, 7), vshlq_n_u32(x, 32 - 7)); return vsriq_n_u32(vshlq_n_u32(x, 32-7), x, 7); } // TODO: compress_neon // TODO: hash2_neon /* * ---------------------------------------------------------------------------- * hash4_neon * ---------------------------------------------------------------------------- */ INLINE void round_fn4(uint32x4_t v[16], uint32x4_t m[16], size_t r) { v[0] = add_128(v[0], m[(size_t)MSG_SCHEDULE[r][0]]); v[1] = add_128(v[1], m[(size_t)MSG_SCHEDULE[r][2]]); v[2] = add_128(v[2], m[(size_t)MSG_SCHEDULE[r][4]]); v[3] = add_128(v[3], m[(size_t)MSG_SCHEDULE[r][6]]); v[0] = add_128(v[0], v[4]); v[1] = add_128(v[1], v[5]); v[2] = add_128(v[2], v[6]); v[3] = add_128(v[3], v[7]); v[12] = xor_128(v[12], v[0]); v[13] = xor_128(v[13], v[1]); v[14] = xor_128(v[14], v[2]); v[15] = xor_128(v[15], v[3]); v[12] = rot16_128(v[12]); v[13] = rot16_128(v[13]); v[14] = rot16_128(v[14]); v[15] = rot16_128(v[15]); v[8] = add_128(v[8], v[12]); v[9] = add_128(v[9], v[13]); v[10] = add_128(v[10], v[14]); v[11] = add_128(v[11], v[15]); v[4] = xor_128(v[4], v[8]); v[5] = xor_128(v[5], v[9]); v[6] = xor_128(v[6], v[10]); v[7] = xor_128(v[7], v[11]); v[4] = rot12_128(v[4]); v[5] = rot12_128(v[5]); v[6] = rot12_128(v[6]); v[7] = rot12_128(v[7]); v[0] = add_128(v[0], m[(size_t)MSG_SCHEDULE[r][1]]); v[1] = add_128(v[1], m[(size_t)MSG_SCHEDULE[r][3]]); v[2] = add_128(v[2], m[(size_t)MSG_SCHEDULE[r][5]]); v[3] = add_128(v[3], m[(size_t)MSG_SCHEDULE[r][7]]); v[0] = add_128(v[0], v[4]); v[1] = add_128(v[1], v[5]); v[2] = add_128(v[2], v[6]); v[3] = add_128(v[3], v[7]); v[12] = xor_128(v[12], v[0]); v[13] = xor_128(v[13], v[1]); v[14] = xor_128(v[14], v[2]); v[15] = xor_128(v[15], v[3]); v[12] = rot8_128(v[12]); v[13] = rot8_128(v[13]); v[14] = rot8_128(v[14]); v[15] = rot8_128(v[15]); v[8] = add_128(v[8], v[12]); v[9] = add_128(v[9], v[13]); v[10] = add_128(v[10], v[14]); v[11] = add_128(v[11], v[15]); v[4] = xor_128(v[4], v[8]); v[5] = xor_128(v[5], v[9]); v[6] = xor_128(v[6], v[10]); v[7] = xor_128(v[7], v[11]); v[4] = rot7_128(v[4]); v[5] = rot7_128(v[5]); v[6] = rot7_128(v[6]); v[7] = rot7_128(v[7]); v[0] = add_128(v[0], m[(size_t)MSG_SCHEDULE[r][8]]); v[1] = add_128(v[1], m[(size_t)MSG_SCHEDULE[r][10]]); v[2] = add_128(v[2], m[(size_t)MSG_SCHEDULE[r][12]]); v[3] = add_128(v[3], m[(size_t)MSG_SCHEDULE[r][14]]); v[0] = add_128(v[0], v[5]); v[1] = add_128(v[1], v[6]); v[2] = add_128(v[2], v[7]); v[3] = add_128(v[3], v[4]); v[15] = xor_128(v[15], v[0]); v[12] = xor_128(v[12], v[1]); v[13] = xor_128(v[13], v[2]); v[14] = xor_128(v[14], v[3]); v[15] = rot16_128(v[15]); v[12] = rot16_128(v[12]); v[13] = rot16_128(v[13]); v[14] = rot16_128(v[14]); v[10] = add_128(v[10], v[15]); v[11] = add_128(v[11], v[12]); v[8] = add_128(v[8], v[13]); v[9] = add_128(v[9], v[14]); v[5] = xor_128(v[5], v[10]); v[6] = xor_128(v[6], v[11]); v[7] = xor_128(v[7], v[8]); v[4] = xor_128(v[4], v[9]); v[5] = rot12_128(v[5]); v[6] = rot12_128(v[6]); v[7] = rot12_128(v[7]); v[4] = rot12_128(v[4]); v[0] = add_128(v[0], m[(size_t)MSG_SCHEDULE[r][9]]); v[1] = add_128(v[1], m[(size_t)MSG_SCHEDULE[r][11]]); v[2] = add_128(v[2], m[(size_t)MSG_SCHEDULE[r][13]]); v[3] = add_128(v[3], m[(size_t)MSG_SCHEDULE[r][15]]); v[0] = add_128(v[0], v[5]); v[1] = add_128(v[1], v[6]); v[2] = add_128(v[2], v[7]); v[3] = add_128(v[3], v[4]); v[15] = xor_128(v[15], v[0]); v[12] = xor_128(v[12], v[1]); v[13] = xor_128(v[13], v[2]); v[14] = xor_128(v[14], v[3]); v[15] = rot8_128(v[15]); v[12] = rot8_128(v[12]); v[13] = rot8_128(v[13]); v[14] = rot8_128(v[14]); v[10] = add_128(v[10], v[15]); v[11] = add_128(v[11], v[12]); v[8] = add_128(v[8], v[13]); v[9] = add_128(v[9], v[14]); v[5] = xor_128(v[5], v[10]); v[6] = xor_128(v[6], v[11]); v[7] = xor_128(v[7], v[8]); v[4] = xor_128(v[4], v[9]); v[5] = rot7_128(v[5]); v[6] = rot7_128(v[6]); v[7] = rot7_128(v[7]); v[4] = rot7_128(v[4]); } INLINE void transpose_vecs_128(uint32x4_t vecs[4]) { // Individually transpose the four 2x2 sub-matrices in each corner. uint32x4x2_t rows01 = vtrnq_u32(vecs[0], vecs[1]); uint32x4x2_t rows23 = vtrnq_u32(vecs[2], vecs[3]); // Swap the top-right and bottom-left 2x2s (which just got transposed). vecs[0] = vcombine_u32(vget_low_u32(rows01.val[0]), vget_low_u32(rows23.val[0])); vecs[1] = vcombine_u32(vget_low_u32(rows01.val[1]), vget_low_u32(rows23.val[1])); vecs[2] = vcombine_u32(vget_high_u32(rows01.val[0]), vget_high_u32(rows23.val[0])); vecs[3] = vcombine_u32(vget_high_u32(rows01.val[1]), vget_high_u32(rows23.val[1])); } INLINE void transpose_msg_vecs4(const uint8_t *const *inputs, size_t block_offset, uint32x4_t out[16]) { out[0] = loadu_128(&inputs[0][block_offset + 0 * sizeof(uint32x4_t)]); out[1] = loadu_128(&inputs[1][block_offset + 0 * sizeof(uint32x4_t)]); out[2] = loadu_128(&inputs[2][block_offset + 0 * sizeof(uint32x4_t)]); out[3] = loadu_128(&inputs[3][block_offset + 0 * sizeof(uint32x4_t)]); out[4] = loadu_128(&inputs[0][block_offset + 1 * sizeof(uint32x4_t)]); out[5] = loadu_128(&inputs[1][block_offset + 1 * sizeof(uint32x4_t)]); out[6] = loadu_128(&inputs[2][block_offset + 1 * sizeof(uint32x4_t)]); out[7] = loadu_128(&inputs[3][block_offset + 1 * sizeof(uint32x4_t)]); out[8] = loadu_128(&inputs[0][block_offset + 2 * sizeof(uint32x4_t)]); out[9] = loadu_128(&inputs[1][block_offset + 2 * sizeof(uint32x4_t)]); out[10] = loadu_128(&inputs[2][block_offset + 2 * sizeof(uint32x4_t)]); out[11] = loadu_128(&inputs[3][block_offset + 2 * sizeof(uint32x4_t)]); out[12] = loadu_128(&inputs[0][block_offset + 3 * sizeof(uint32x4_t)]); out[13] = loadu_128(&inputs[1][block_offset + 3 * sizeof(uint32x4_t)]); out[14] = loadu_128(&inputs[2][block_offset + 3 * sizeof(uint32x4_t)]); out[15] = loadu_128(&inputs[3][block_offset + 3 * sizeof(uint32x4_t)]); transpose_vecs_128(&out[0]); transpose_vecs_128(&out[4]); transpose_vecs_128(&out[8]); transpose_vecs_128(&out[12]); } INLINE void load_counters4(uint64_t counter, bool increment_counter, uint32x4_t *out_low, uint32x4_t *out_high) { uint64_t mask = (increment_counter ? ~0 : 0); *out_low = set4( counter_low(counter + (mask & 0)), counter_low(counter + (mask & 1)), counter_low(counter + (mask & 2)), counter_low(counter + (mask & 3))); *out_high = set4( counter_high(counter + (mask & 0)), counter_high(counter + (mask & 1)), counter_high(counter + (mask & 2)), counter_high(counter + (mask & 3))); } void blake3_hash4_neon(const uint8_t *const *inputs, size_t blocks, const uint32_t key[8], uint64_t counter, bool increment_counter, uint8_t flags, uint8_t flags_start, uint8_t flags_end, uint8_t *out) { uint32x4_t h_vecs[8] = { set1_128(key[0]), set1_128(key[1]), set1_128(key[2]), set1_128(key[3]), set1_128(key[4]), set1_128(key[5]), set1_128(key[6]), set1_128(key[7]), }; uint32x4_t counter_low_vec, counter_high_vec; load_counters4(counter, increment_counter, &counter_low_vec, &counter_high_vec); uint8_t block_flags = flags | flags_start; for (size_t block = 0; block < blocks; block++) { if (block + 1 == blocks) { block_flags |= flags_end; } uint32x4_t block_len_vec = set1_128(BLAKE3_BLOCK_LEN); uint32x4_t block_flags_vec = set1_128(block_flags); uint32x4_t msg_vecs[16]; transpose_msg_vecs4(inputs, block * BLAKE3_BLOCK_LEN, msg_vecs); uint32x4_t v[16] = { h_vecs[0], h_vecs[1], h_vecs[2], h_vecs[3], h_vecs[4], h_vecs[5], h_vecs[6], h_vecs[7], set1_128(IV[0]), set1_128(IV[1]), set1_128(IV[2]), set1_128(IV[3]), counter_low_vec, counter_high_vec, block_len_vec, block_flags_vec, }; round_fn4(v, msg_vecs, 0); round_fn4(v, msg_vecs, 1); round_fn4(v, msg_vecs, 2); round_fn4(v, msg_vecs, 3); round_fn4(v, msg_vecs, 4); round_fn4(v, msg_vecs, 5); round_fn4(v, msg_vecs, 6); h_vecs[0] = xor_128(v[0], v[8]); h_vecs[1] = xor_128(v[1], v[9]); h_vecs[2] = xor_128(v[2], v[10]); h_vecs[3] = xor_128(v[3], v[11]); h_vecs[4] = xor_128(v[4], v[12]); h_vecs[5] = xor_128(v[5], v[13]); h_vecs[6] = xor_128(v[6], v[14]); h_vecs[7] = xor_128(v[7], v[15]); block_flags = flags; } transpose_vecs_128(&h_vecs[0]); transpose_vecs_128(&h_vecs[4]); // The first four vecs now contain the first half of each output, and the // second four vecs contain the second half of each output. storeu_128(h_vecs[0], &out[0 * sizeof(uint32x4_t)]); storeu_128(h_vecs[4], &out[1 * sizeof(uint32x4_t)]); storeu_128(h_vecs[1], &out[2 * sizeof(uint32x4_t)]); storeu_128(h_vecs[5], &out[3 * sizeof(uint32x4_t)]); storeu_128(h_vecs[2], &out[4 * sizeof(uint32x4_t)]); storeu_128(h_vecs[6], &out[5 * sizeof(uint32x4_t)]); storeu_128(h_vecs[3], &out[6 * sizeof(uint32x4_t)]); storeu_128(h_vecs[7], &out[7 * sizeof(uint32x4_t)]); } /* * ---------------------------------------------------------------------------- * hash_many_neon * ---------------------------------------------------------------------------- */ void blake3_compress_in_place_portable(uint32_t cv[8], const uint8_t block[BLAKE3_BLOCK_LEN], uint8_t block_len, uint64_t counter, uint8_t flags); INLINE void hash_one_neon(const uint8_t *input, size_t blocks, const uint32_t key[8], uint64_t counter, uint8_t flags, uint8_t flags_start, uint8_t flags_end, uint8_t out[BLAKE3_OUT_LEN]) { uint32_t cv[8]; memcpy(cv, key, BLAKE3_KEY_LEN); uint8_t block_flags = flags | flags_start; while (blocks > 0) { if (blocks == 1) { block_flags |= flags_end; } // TODO: Implement compress_neon. However note that according to // https://github.com/BLAKE2/BLAKE2/commit/7965d3e6e1b4193438b8d3a656787587d2579227, // compress_neon might not be any faster than compress_portable. blake3_compress_in_place_portable(cv, input, BLAKE3_BLOCK_LEN, counter, block_flags); input = &input[BLAKE3_BLOCK_LEN]; blocks -= 1; block_flags = flags; } memcpy(out, cv, BLAKE3_OUT_LEN); } void blake3_hash_many_neon(const uint8_t *const *inputs, size_t num_inputs, size_t blocks, const uint32_t key[8], uint64_t counter, bool increment_counter, uint8_t flags, uint8_t flags_start, uint8_t flags_end, uint8_t *out) { while (num_inputs >= 4) { blake3_hash4_neon(inputs, blocks, key, counter, increment_counter, flags, flags_start, flags_end, out); if (increment_counter) { counter += 4; } inputs += 4; num_inputs -= 4; out = &out[4 * BLAKE3_OUT_LEN]; } while (num_inputs > 0) { hash_one_neon(inputs[0], blocks, key, counter, flags, flags_start, flags_end, out); if (increment_counter) { counter += 1; } inputs += 1; num_inputs -= 1; out = &out[BLAKE3_OUT_LEN]; } } librecast/libs/blake3/c/blake3_portable.c000066400000000000000000000134011502456746400205530ustar00rootroot00000000000000#include "blake3_impl.h" #include INLINE uint32_t rotr32(uint32_t w, uint32_t c) { return (w >> c) | (w << (32 - c)); } INLINE void g(uint32_t *state, size_t a, size_t b, size_t c, size_t d, uint32_t x, uint32_t y) { state[a] = state[a] + state[b] + x; state[d] = rotr32(state[d] ^ state[a], 16); state[c] = state[c] + state[d]; state[b] = rotr32(state[b] ^ state[c], 12); state[a] = state[a] + state[b] + y; state[d] = rotr32(state[d] ^ state[a], 8); state[c] = state[c] + state[d]; state[b] = rotr32(state[b] ^ state[c], 7); } INLINE void round_fn(uint32_t state[16], const uint32_t *msg, size_t round) { // Select the message schedule based on the round. const uint8_t *schedule = MSG_SCHEDULE[round]; // Mix the columns. g(state, 0, 4, 8, 12, msg[schedule[0]], msg[schedule[1]]); g(state, 1, 5, 9, 13, msg[schedule[2]], msg[schedule[3]]); g(state, 2, 6, 10, 14, msg[schedule[4]], msg[schedule[5]]); g(state, 3, 7, 11, 15, msg[schedule[6]], msg[schedule[7]]); // Mix the rows. g(state, 0, 5, 10, 15, msg[schedule[8]], msg[schedule[9]]); g(state, 1, 6, 11, 12, msg[schedule[10]], msg[schedule[11]]); g(state, 2, 7, 8, 13, msg[schedule[12]], msg[schedule[13]]); g(state, 3, 4, 9, 14, msg[schedule[14]], msg[schedule[15]]); } INLINE void compress_pre(uint32_t state[16], const uint32_t cv[8], const uint8_t block[BLAKE3_BLOCK_LEN], uint8_t block_len, uint64_t counter, uint8_t flags) { uint32_t block_words[16]; block_words[0] = load32(block + 4 * 0); block_words[1] = load32(block + 4 * 1); block_words[2] = load32(block + 4 * 2); block_words[3] = load32(block + 4 * 3); block_words[4] = load32(block + 4 * 4); block_words[5] = load32(block + 4 * 5); block_words[6] = load32(block + 4 * 6); block_words[7] = load32(block + 4 * 7); block_words[8] = load32(block + 4 * 8); block_words[9] = load32(block + 4 * 9); block_words[10] = load32(block + 4 * 10); block_words[11] = load32(block + 4 * 11); block_words[12] = load32(block + 4 * 12); block_words[13] = load32(block + 4 * 13); block_words[14] = load32(block + 4 * 14); block_words[15] = load32(block + 4 * 15); state[0] = cv[0]; state[1] = cv[1]; state[2] = cv[2]; state[3] = cv[3]; state[4] = cv[4]; state[5] = cv[5]; state[6] = cv[6]; state[7] = cv[7]; state[8] = IV[0]; state[9] = IV[1]; state[10] = IV[2]; state[11] = IV[3]; state[12] = counter_low(counter); state[13] = counter_high(counter); state[14] = (uint32_t)block_len; state[15] = (uint32_t)flags; round_fn(state, &block_words[0], 0); round_fn(state, &block_words[0], 1); round_fn(state, &block_words[0], 2); round_fn(state, &block_words[0], 3); round_fn(state, &block_words[0], 4); round_fn(state, &block_words[0], 5); round_fn(state, &block_words[0], 6); } void blake3_compress_in_place_portable(uint32_t cv[8], const uint8_t block[BLAKE3_BLOCK_LEN], uint8_t block_len, uint64_t counter, uint8_t flags) { uint32_t state[16]; compress_pre(state, cv, block, block_len, counter, flags); cv[0] = state[0] ^ state[8]; cv[1] = state[1] ^ state[9]; cv[2] = state[2] ^ state[10]; cv[3] = state[3] ^ state[11]; cv[4] = state[4] ^ state[12]; cv[5] = state[5] ^ state[13]; cv[6] = state[6] ^ state[14]; cv[7] = state[7] ^ state[15]; } void blake3_compress_xof_portable(const uint32_t cv[8], const uint8_t block[BLAKE3_BLOCK_LEN], uint8_t block_len, uint64_t counter, uint8_t flags, uint8_t out[64]) { uint32_t state[16]; compress_pre(state, cv, block, block_len, counter, flags); store32(&out[0 * 4], state[0] ^ state[8]); store32(&out[1 * 4], state[1] ^ state[9]); store32(&out[2 * 4], state[2] ^ state[10]); store32(&out[3 * 4], state[3] ^ state[11]); store32(&out[4 * 4], state[4] ^ state[12]); store32(&out[5 * 4], state[5] ^ state[13]); store32(&out[6 * 4], state[6] ^ state[14]); store32(&out[7 * 4], state[7] ^ state[15]); store32(&out[8 * 4], state[8] ^ cv[0]); store32(&out[9 * 4], state[9] ^ cv[1]); store32(&out[10 * 4], state[10] ^ cv[2]); store32(&out[11 * 4], state[11] ^ cv[3]); store32(&out[12 * 4], state[12] ^ cv[4]); store32(&out[13 * 4], state[13] ^ cv[5]); store32(&out[14 * 4], state[14] ^ cv[6]); store32(&out[15 * 4], state[15] ^ cv[7]); } INLINE void hash_one_portable(const uint8_t *input, size_t blocks, const uint32_t key[8], uint64_t counter, uint8_t flags, uint8_t flags_start, uint8_t flags_end, uint8_t out[BLAKE3_OUT_LEN]) { uint32_t cv[8]; memcpy(cv, key, BLAKE3_KEY_LEN); uint8_t block_flags = flags | flags_start; while (blocks > 0) { if (blocks == 1) { block_flags |= flags_end; } blake3_compress_in_place_portable(cv, input, BLAKE3_BLOCK_LEN, counter, block_flags); input = &input[BLAKE3_BLOCK_LEN]; blocks -= 1; block_flags = flags; } store_cv_words(out, cv); } void blake3_hash_many_portable(const uint8_t *const *inputs, size_t num_inputs, size_t blocks, const uint32_t key[8], uint64_t counter, bool increment_counter, uint8_t flags, uint8_t flags_start, uint8_t flags_end, uint8_t *out) { while (num_inputs > 0) { hash_one_portable(inputs[0], blocks, key, counter, flags, flags_start, flags_end, out); if (increment_counter) { counter += 1; } inputs += 1; num_inputs -= 1; out = &out[BLAKE3_OUT_LEN]; } } librecast/libs/blake3/c/blake3_sse2.c000066400000000000000000000510151502456746400176220ustar00rootroot00000000000000#include "blake3_impl.h" #include #define DEGREE 4 #define _mm_shuffle_ps2(a, b, c) \ (_mm_castps_si128( \ _mm_shuffle_ps(_mm_castsi128_ps(a), _mm_castsi128_ps(b), (c)))) INLINE __m128i loadu(const uint8_t src[16]) { return _mm_loadu_si128((const __m128i *)src); } INLINE void storeu(__m128i src, uint8_t dest[16]) { _mm_storeu_si128((__m128i *)dest, src); } INLINE __m128i addv(__m128i a, __m128i b) { return _mm_add_epi32(a, b); } // Note that clang-format doesn't like the name "xor" for some reason. INLINE __m128i xorv(__m128i a, __m128i b) { return _mm_xor_si128(a, b); } INLINE __m128i set1(uint32_t x) { return _mm_set1_epi32((int32_t)x); } INLINE __m128i set4(uint32_t a, uint32_t b, uint32_t c, uint32_t d) { return _mm_setr_epi32((int32_t)a, (int32_t)b, (int32_t)c, (int32_t)d); } INLINE __m128i rot16(__m128i x) { return _mm_shufflehi_epi16(_mm_shufflelo_epi16(x, 0xB1), 0xB1); } INLINE __m128i rot12(__m128i x) { return xorv(_mm_srli_epi32(x, 12), _mm_slli_epi32(x, 32 - 12)); } INLINE __m128i rot8(__m128i x) { return xorv(_mm_srli_epi32(x, 8), _mm_slli_epi32(x, 32 - 8)); } INLINE __m128i rot7(__m128i x) { return xorv(_mm_srli_epi32(x, 7), _mm_slli_epi32(x, 32 - 7)); } INLINE void g1(__m128i *row0, __m128i *row1, __m128i *row2, __m128i *row3, __m128i m) { *row0 = addv(addv(*row0, m), *row1); *row3 = xorv(*row3, *row0); *row3 = rot16(*row3); *row2 = addv(*row2, *row3); *row1 = xorv(*row1, *row2); *row1 = rot12(*row1); } INLINE void g2(__m128i *row0, __m128i *row1, __m128i *row2, __m128i *row3, __m128i m) { *row0 = addv(addv(*row0, m), *row1); *row3 = xorv(*row3, *row0); *row3 = rot8(*row3); *row2 = addv(*row2, *row3); *row1 = xorv(*row1, *row2); *row1 = rot7(*row1); } // Note the optimization here of leaving row1 as the unrotated row, rather than // row0. All the message loads below are adjusted to compensate for this. See // discussion at https://github.com/sneves/blake2-avx2/pull/4 INLINE void diagonalize(__m128i *row0, __m128i *row2, __m128i *row3) { *row0 = _mm_shuffle_epi32(*row0, _MM_SHUFFLE(2, 1, 0, 3)); *row3 = _mm_shuffle_epi32(*row3, _MM_SHUFFLE(1, 0, 3, 2)); *row2 = _mm_shuffle_epi32(*row2, _MM_SHUFFLE(0, 3, 2, 1)); } INLINE void undiagonalize(__m128i *row0, __m128i *row2, __m128i *row3) { *row0 = _mm_shuffle_epi32(*row0, _MM_SHUFFLE(0, 3, 2, 1)); *row3 = _mm_shuffle_epi32(*row3, _MM_SHUFFLE(1, 0, 3, 2)); *row2 = _mm_shuffle_epi32(*row2, _MM_SHUFFLE(2, 1, 0, 3)); } INLINE __m128i blend_epi16(__m128i a, __m128i b, const int16_t imm8) { const __m128i bits = _mm_set_epi16(0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01); __m128i mask = _mm_set1_epi16(imm8); mask = _mm_and_si128(mask, bits); mask = _mm_cmpeq_epi16(mask, bits); return _mm_or_si128(_mm_and_si128(mask, b), _mm_andnot_si128(mask, a)); } INLINE void compress_pre(__m128i rows[4], const uint32_t cv[8], const uint8_t block[BLAKE3_BLOCK_LEN], uint8_t block_len, uint64_t counter, uint8_t flags) { rows[0] = loadu((uint8_t *)&cv[0]); rows[1] = loadu((uint8_t *)&cv[4]); rows[2] = set4(IV[0], IV[1], IV[2], IV[3]); rows[3] = set4(counter_low(counter), counter_high(counter), (uint32_t)block_len, (uint32_t)flags); __m128i m0 = loadu(&block[sizeof(__m128i) * 0]); __m128i m1 = loadu(&block[sizeof(__m128i) * 1]); __m128i m2 = loadu(&block[sizeof(__m128i) * 2]); __m128i m3 = loadu(&block[sizeof(__m128i) * 3]); __m128i t0, t1, t2, t3, tt; // Round 1. The first round permutes the message words from the original // input order, into the groups that get mixed in parallel. t0 = _mm_shuffle_ps2(m0, m1, _MM_SHUFFLE(2, 0, 2, 0)); // 6 4 2 0 g1(&rows[0], &rows[1], &rows[2], &rows[3], t0); t1 = _mm_shuffle_ps2(m0, m1, _MM_SHUFFLE(3, 1, 3, 1)); // 7 5 3 1 g2(&rows[0], &rows[1], &rows[2], &rows[3], t1); diagonalize(&rows[0], &rows[2], &rows[3]); t2 = _mm_shuffle_ps2(m2, m3, _MM_SHUFFLE(2, 0, 2, 0)); // 14 12 10 8 t2 = _mm_shuffle_epi32(t2, _MM_SHUFFLE(2, 1, 0, 3)); // 12 10 8 14 g1(&rows[0], &rows[1], &rows[2], &rows[3], t2); t3 = _mm_shuffle_ps2(m2, m3, _MM_SHUFFLE(3, 1, 3, 1)); // 15 13 11 9 t3 = _mm_shuffle_epi32(t3, _MM_SHUFFLE(2, 1, 0, 3)); // 13 11 9 15 g2(&rows[0], &rows[1], &rows[2], &rows[3], t3); undiagonalize(&rows[0], &rows[2], &rows[3]); m0 = t0; m1 = t1; m2 = t2; m3 = t3; // Round 2. This round and all following rounds apply a fixed permutation // to the message words from the round before. t0 = _mm_shuffle_ps2(m0, m1, _MM_SHUFFLE(3, 1, 1, 2)); t0 = _mm_shuffle_epi32(t0, _MM_SHUFFLE(0, 3, 2, 1)); g1(&rows[0], &rows[1], &rows[2], &rows[3], t0); t1 = _mm_shuffle_ps2(m2, m3, _MM_SHUFFLE(3, 3, 2, 2)); tt = _mm_shuffle_epi32(m0, _MM_SHUFFLE(0, 0, 3, 3)); t1 = blend_epi16(tt, t1, 0xCC); g2(&rows[0], &rows[1], &rows[2], &rows[3], t1); diagonalize(&rows[0], &rows[2], &rows[3]); t2 = _mm_unpacklo_epi64(m3, m1); tt = blend_epi16(t2, m2, 0xC0); t2 = _mm_shuffle_epi32(tt, _MM_SHUFFLE(1, 3, 2, 0)); g1(&rows[0], &rows[1], &rows[2], &rows[3], t2); t3 = _mm_unpackhi_epi32(m1, m3); tt = _mm_unpacklo_epi32(m2, t3); t3 = _mm_shuffle_epi32(tt, _MM_SHUFFLE(0, 1, 3, 2)); g2(&rows[0], &rows[1], &rows[2], &rows[3], t3); undiagonalize(&rows[0], &rows[2], &rows[3]); m0 = t0; m1 = t1; m2 = t2; m3 = t3; // Round 3 t0 = _mm_shuffle_ps2(m0, m1, _MM_SHUFFLE(3, 1, 1, 2)); t0 = _mm_shuffle_epi32(t0, _MM_SHUFFLE(0, 3, 2, 1)); g1(&rows[0], &rows[1], &rows[2], &rows[3], t0); t1 = _mm_shuffle_ps2(m2, m3, _MM_SHUFFLE(3, 3, 2, 2)); tt = _mm_shuffle_epi32(m0, _MM_SHUFFLE(0, 0, 3, 3)); t1 = blend_epi16(tt, t1, 0xCC); g2(&rows[0], &rows[1], &rows[2], &rows[3], t1); diagonalize(&rows[0], &rows[2], &rows[3]); t2 = _mm_unpacklo_epi64(m3, m1); tt = blend_epi16(t2, m2, 0xC0); t2 = _mm_shuffle_epi32(tt, _MM_SHUFFLE(1, 3, 2, 0)); g1(&rows[0], &rows[1], &rows[2], &rows[3], t2); t3 = _mm_unpackhi_epi32(m1, m3); tt = _mm_unpacklo_epi32(m2, t3); t3 = _mm_shuffle_epi32(tt, _MM_SHUFFLE(0, 1, 3, 2)); g2(&rows[0], &rows[1], &rows[2], &rows[3], t3); undiagonalize(&rows[0], &rows[2], &rows[3]); m0 = t0; m1 = t1; m2 = t2; m3 = t3; // Round 4 t0 = _mm_shuffle_ps2(m0, m1, _MM_SHUFFLE(3, 1, 1, 2)); t0 = _mm_shuffle_epi32(t0, _MM_SHUFFLE(0, 3, 2, 1)); g1(&rows[0], &rows[1], &rows[2], &rows[3], t0); t1 = _mm_shuffle_ps2(m2, m3, _MM_SHUFFLE(3, 3, 2, 2)); tt = _mm_shuffle_epi32(m0, _MM_SHUFFLE(0, 0, 3, 3)); t1 = blend_epi16(tt, t1, 0xCC); g2(&rows[0], &rows[1], &rows[2], &rows[3], t1); diagonalize(&rows[0], &rows[2], &rows[3]); t2 = _mm_unpacklo_epi64(m3, m1); tt = blend_epi16(t2, m2, 0xC0); t2 = _mm_shuffle_epi32(tt, _MM_SHUFFLE(1, 3, 2, 0)); g1(&rows[0], &rows[1], &rows[2], &rows[3], t2); t3 = _mm_unpackhi_epi32(m1, m3); tt = _mm_unpacklo_epi32(m2, t3); t3 = _mm_shuffle_epi32(tt, _MM_SHUFFLE(0, 1, 3, 2)); g2(&rows[0], &rows[1], &rows[2], &rows[3], t3); undiagonalize(&rows[0], &rows[2], &rows[3]); m0 = t0; m1 = t1; m2 = t2; m3 = t3; // Round 5 t0 = _mm_shuffle_ps2(m0, m1, _MM_SHUFFLE(3, 1, 1, 2)); t0 = _mm_shuffle_epi32(t0, _MM_SHUFFLE(0, 3, 2, 1)); g1(&rows[0], &rows[1], &rows[2], &rows[3], t0); t1 = _mm_shuffle_ps2(m2, m3, _MM_SHUFFLE(3, 3, 2, 2)); tt = _mm_shuffle_epi32(m0, _MM_SHUFFLE(0, 0, 3, 3)); t1 = blend_epi16(tt, t1, 0xCC); g2(&rows[0], &rows[1], &rows[2], &rows[3], t1); diagonalize(&rows[0], &rows[2], &rows[3]); t2 = _mm_unpacklo_epi64(m3, m1); tt = blend_epi16(t2, m2, 0xC0); t2 = _mm_shuffle_epi32(tt, _MM_SHUFFLE(1, 3, 2, 0)); g1(&rows[0], &rows[1], &rows[2], &rows[3], t2); t3 = _mm_unpackhi_epi32(m1, m3); tt = _mm_unpacklo_epi32(m2, t3); t3 = _mm_shuffle_epi32(tt, _MM_SHUFFLE(0, 1, 3, 2)); g2(&rows[0], &rows[1], &rows[2], &rows[3], t3); undiagonalize(&rows[0], &rows[2], &rows[3]); m0 = t0; m1 = t1; m2 = t2; m3 = t3; // Round 6 t0 = _mm_shuffle_ps2(m0, m1, _MM_SHUFFLE(3, 1, 1, 2)); t0 = _mm_shuffle_epi32(t0, _MM_SHUFFLE(0, 3, 2, 1)); g1(&rows[0], &rows[1], &rows[2], &rows[3], t0); t1 = _mm_shuffle_ps2(m2, m3, _MM_SHUFFLE(3, 3, 2, 2)); tt = _mm_shuffle_epi32(m0, _MM_SHUFFLE(0, 0, 3, 3)); t1 = blend_epi16(tt, t1, 0xCC); g2(&rows[0], &rows[1], &rows[2], &rows[3], t1); diagonalize(&rows[0], &rows[2], &rows[3]); t2 = _mm_unpacklo_epi64(m3, m1); tt = blend_epi16(t2, m2, 0xC0); t2 = _mm_shuffle_epi32(tt, _MM_SHUFFLE(1, 3, 2, 0)); g1(&rows[0], &rows[1], &rows[2], &rows[3], t2); t3 = _mm_unpackhi_epi32(m1, m3); tt = _mm_unpacklo_epi32(m2, t3); t3 = _mm_shuffle_epi32(tt, _MM_SHUFFLE(0, 1, 3, 2)); g2(&rows[0], &rows[1], &rows[2], &rows[3], t3); undiagonalize(&rows[0], &rows[2], &rows[3]); m0 = t0; m1 = t1; m2 = t2; m3 = t3; // Round 7 t0 = _mm_shuffle_ps2(m0, m1, _MM_SHUFFLE(3, 1, 1, 2)); t0 = _mm_shuffle_epi32(t0, _MM_SHUFFLE(0, 3, 2, 1)); g1(&rows[0], &rows[1], &rows[2], &rows[3], t0); t1 = _mm_shuffle_ps2(m2, m3, _MM_SHUFFLE(3, 3, 2, 2)); tt = _mm_shuffle_epi32(m0, _MM_SHUFFLE(0, 0, 3, 3)); t1 = blend_epi16(tt, t1, 0xCC); g2(&rows[0], &rows[1], &rows[2], &rows[3], t1); diagonalize(&rows[0], &rows[2], &rows[3]); t2 = _mm_unpacklo_epi64(m3, m1); tt = blend_epi16(t2, m2, 0xC0); t2 = _mm_shuffle_epi32(tt, _MM_SHUFFLE(1, 3, 2, 0)); g1(&rows[0], &rows[1], &rows[2], &rows[3], t2); t3 = _mm_unpackhi_epi32(m1, m3); tt = _mm_unpacklo_epi32(m2, t3); t3 = _mm_shuffle_epi32(tt, _MM_SHUFFLE(0, 1, 3, 2)); g2(&rows[0], &rows[1], &rows[2], &rows[3], t3); undiagonalize(&rows[0], &rows[2], &rows[3]); } void blake3_compress_in_place_sse2(uint32_t cv[8], const uint8_t block[BLAKE3_BLOCK_LEN], uint8_t block_len, uint64_t counter, uint8_t flags) { __m128i rows[4]; compress_pre(rows, cv, block, block_len, counter, flags); storeu(xorv(rows[0], rows[2]), (uint8_t *)&cv[0]); storeu(xorv(rows[1], rows[3]), (uint8_t *)&cv[4]); } void blake3_compress_xof_sse2(const uint32_t cv[8], const uint8_t block[BLAKE3_BLOCK_LEN], uint8_t block_len, uint64_t counter, uint8_t flags, uint8_t out[64]) { __m128i rows[4]; compress_pre(rows, cv, block, block_len, counter, flags); storeu(xorv(rows[0], rows[2]), &out[0]); storeu(xorv(rows[1], rows[3]), &out[16]); storeu(xorv(rows[2], loadu((uint8_t *)&cv[0])), &out[32]); storeu(xorv(rows[3], loadu((uint8_t *)&cv[4])), &out[48]); } INLINE void round_fn(__m128i v[16], __m128i m[16], size_t r) { v[0] = addv(v[0], m[(size_t)MSG_SCHEDULE[r][0]]); v[1] = addv(v[1], m[(size_t)MSG_SCHEDULE[r][2]]); v[2] = addv(v[2], m[(size_t)MSG_SCHEDULE[r][4]]); v[3] = addv(v[3], m[(size_t)MSG_SCHEDULE[r][6]]); v[0] = addv(v[0], v[4]); v[1] = addv(v[1], v[5]); v[2] = addv(v[2], v[6]); v[3] = addv(v[3], v[7]); v[12] = xorv(v[12], v[0]); v[13] = xorv(v[13], v[1]); v[14] = xorv(v[14], v[2]); v[15] = xorv(v[15], v[3]); v[12] = rot16(v[12]); v[13] = rot16(v[13]); v[14] = rot16(v[14]); v[15] = rot16(v[15]); v[8] = addv(v[8], v[12]); v[9] = addv(v[9], v[13]); v[10] = addv(v[10], v[14]); v[11] = addv(v[11], v[15]); v[4] = xorv(v[4], v[8]); v[5] = xorv(v[5], v[9]); v[6] = xorv(v[6], v[10]); v[7] = xorv(v[7], v[11]); v[4] = rot12(v[4]); v[5] = rot12(v[5]); v[6] = rot12(v[6]); v[7] = rot12(v[7]); v[0] = addv(v[0], m[(size_t)MSG_SCHEDULE[r][1]]); v[1] = addv(v[1], m[(size_t)MSG_SCHEDULE[r][3]]); v[2] = addv(v[2], m[(size_t)MSG_SCHEDULE[r][5]]); v[3] = addv(v[3], m[(size_t)MSG_SCHEDULE[r][7]]); v[0] = addv(v[0], v[4]); v[1] = addv(v[1], v[5]); v[2] = addv(v[2], v[6]); v[3] = addv(v[3], v[7]); v[12] = xorv(v[12], v[0]); v[13] = xorv(v[13], v[1]); v[14] = xorv(v[14], v[2]); v[15] = xorv(v[15], v[3]); v[12] = rot8(v[12]); v[13] = rot8(v[13]); v[14] = rot8(v[14]); v[15] = rot8(v[15]); v[8] = addv(v[8], v[12]); v[9] = addv(v[9], v[13]); v[10] = addv(v[10], v[14]); v[11] = addv(v[11], v[15]); v[4] = xorv(v[4], v[8]); v[5] = xorv(v[5], v[9]); v[6] = xorv(v[6], v[10]); v[7] = xorv(v[7], v[11]); v[4] = rot7(v[4]); v[5] = rot7(v[5]); v[6] = rot7(v[6]); v[7] = rot7(v[7]); v[0] = addv(v[0], m[(size_t)MSG_SCHEDULE[r][8]]); v[1] = addv(v[1], m[(size_t)MSG_SCHEDULE[r][10]]); v[2] = addv(v[2], m[(size_t)MSG_SCHEDULE[r][12]]); v[3] = addv(v[3], m[(size_t)MSG_SCHEDULE[r][14]]); v[0] = addv(v[0], v[5]); v[1] = addv(v[1], v[6]); v[2] = addv(v[2], v[7]); v[3] = addv(v[3], v[4]); v[15] = xorv(v[15], v[0]); v[12] = xorv(v[12], v[1]); v[13] = xorv(v[13], v[2]); v[14] = xorv(v[14], v[3]); v[15] = rot16(v[15]); v[12] = rot16(v[12]); v[13] = rot16(v[13]); v[14] = rot16(v[14]); v[10] = addv(v[10], v[15]); v[11] = addv(v[11], v[12]); v[8] = addv(v[8], v[13]); v[9] = addv(v[9], v[14]); v[5] = xorv(v[5], v[10]); v[6] = xorv(v[6], v[11]); v[7] = xorv(v[7], v[8]); v[4] = xorv(v[4], v[9]); v[5] = rot12(v[5]); v[6] = rot12(v[6]); v[7] = rot12(v[7]); v[4] = rot12(v[4]); v[0] = addv(v[0], m[(size_t)MSG_SCHEDULE[r][9]]); v[1] = addv(v[1], m[(size_t)MSG_SCHEDULE[r][11]]); v[2] = addv(v[2], m[(size_t)MSG_SCHEDULE[r][13]]); v[3] = addv(v[3], m[(size_t)MSG_SCHEDULE[r][15]]); v[0] = addv(v[0], v[5]); v[1] = addv(v[1], v[6]); v[2] = addv(v[2], v[7]); v[3] = addv(v[3], v[4]); v[15] = xorv(v[15], v[0]); v[12] = xorv(v[12], v[1]); v[13] = xorv(v[13], v[2]); v[14] = xorv(v[14], v[3]); v[15] = rot8(v[15]); v[12] = rot8(v[12]); v[13] = rot8(v[13]); v[14] = rot8(v[14]); v[10] = addv(v[10], v[15]); v[11] = addv(v[11], v[12]); v[8] = addv(v[8], v[13]); v[9] = addv(v[9], v[14]); v[5] = xorv(v[5], v[10]); v[6] = xorv(v[6], v[11]); v[7] = xorv(v[7], v[8]); v[4] = xorv(v[4], v[9]); v[5] = rot7(v[5]); v[6] = rot7(v[6]); v[7] = rot7(v[7]); v[4] = rot7(v[4]); } INLINE void transpose_vecs(__m128i vecs[DEGREE]) { // Interleave 32-bit lanes. The low unpack is lanes 00/11 and the high is // 22/33. Note that this doesn't split the vector into two lanes, as the // AVX2 counterparts do. __m128i ab_01 = _mm_unpacklo_epi32(vecs[0], vecs[1]); __m128i ab_23 = _mm_unpackhi_epi32(vecs[0], vecs[1]); __m128i cd_01 = _mm_unpacklo_epi32(vecs[2], vecs[3]); __m128i cd_23 = _mm_unpackhi_epi32(vecs[2], vecs[3]); // Interleave 64-bit lanes. __m128i abcd_0 = _mm_unpacklo_epi64(ab_01, cd_01); __m128i abcd_1 = _mm_unpackhi_epi64(ab_01, cd_01); __m128i abcd_2 = _mm_unpacklo_epi64(ab_23, cd_23); __m128i abcd_3 = _mm_unpackhi_epi64(ab_23, cd_23); vecs[0] = abcd_0; vecs[1] = abcd_1; vecs[2] = abcd_2; vecs[3] = abcd_3; } INLINE void transpose_msg_vecs(const uint8_t *const *inputs, size_t block_offset, __m128i out[16]) { out[0] = loadu(&inputs[0][block_offset + 0 * sizeof(__m128i)]); out[1] = loadu(&inputs[1][block_offset + 0 * sizeof(__m128i)]); out[2] = loadu(&inputs[2][block_offset + 0 * sizeof(__m128i)]); out[3] = loadu(&inputs[3][block_offset + 0 * sizeof(__m128i)]); out[4] = loadu(&inputs[0][block_offset + 1 * sizeof(__m128i)]); out[5] = loadu(&inputs[1][block_offset + 1 * sizeof(__m128i)]); out[6] = loadu(&inputs[2][block_offset + 1 * sizeof(__m128i)]); out[7] = loadu(&inputs[3][block_offset + 1 * sizeof(__m128i)]); out[8] = loadu(&inputs[0][block_offset + 2 * sizeof(__m128i)]); out[9] = loadu(&inputs[1][block_offset + 2 * sizeof(__m128i)]); out[10] = loadu(&inputs[2][block_offset + 2 * sizeof(__m128i)]); out[11] = loadu(&inputs[3][block_offset + 2 * sizeof(__m128i)]); out[12] = loadu(&inputs[0][block_offset + 3 * sizeof(__m128i)]); out[13] = loadu(&inputs[1][block_offset + 3 * sizeof(__m128i)]); out[14] = loadu(&inputs[2][block_offset + 3 * sizeof(__m128i)]); out[15] = loadu(&inputs[3][block_offset + 3 * sizeof(__m128i)]); for (size_t i = 0; i < 4; ++i) { _mm_prefetch((const void *)&inputs[i][block_offset + 256], _MM_HINT_T0); } transpose_vecs(&out[0]); transpose_vecs(&out[4]); transpose_vecs(&out[8]); transpose_vecs(&out[12]); } INLINE void load_counters(uint64_t counter, bool increment_counter, __m128i *out_lo, __m128i *out_hi) { const __m128i mask = _mm_set1_epi32(-(int32_t)increment_counter); const __m128i add0 = _mm_set_epi32(3, 2, 1, 0); const __m128i add1 = _mm_and_si128(mask, add0); __m128i l = _mm_add_epi32(_mm_set1_epi32((int32_t)counter), add1); __m128i carry = _mm_cmpgt_epi32(_mm_xor_si128(add1, _mm_set1_epi32(0x80000000)), _mm_xor_si128( l, _mm_set1_epi32(0x80000000))); __m128i h = _mm_sub_epi32(_mm_set1_epi32((int32_t)(counter >> 32)), carry); *out_lo = l; *out_hi = h; } static void blake3_hash4_sse2(const uint8_t *const *inputs, size_t blocks, const uint32_t key[8], uint64_t counter, bool increment_counter, uint8_t flags, uint8_t flags_start, uint8_t flags_end, uint8_t *out) { __m128i h_vecs[8] = { set1(key[0]), set1(key[1]), set1(key[2]), set1(key[3]), set1(key[4]), set1(key[5]), set1(key[6]), set1(key[7]), }; __m128i counter_low_vec, counter_high_vec; load_counters(counter, increment_counter, &counter_low_vec, &counter_high_vec); uint8_t block_flags = flags | flags_start; for (size_t block = 0; block < blocks; block++) { if (block + 1 == blocks) { block_flags |= flags_end; } __m128i block_len_vec = set1(BLAKE3_BLOCK_LEN); __m128i block_flags_vec = set1(block_flags); __m128i msg_vecs[16]; transpose_msg_vecs(inputs, block * BLAKE3_BLOCK_LEN, msg_vecs); __m128i v[16] = { h_vecs[0], h_vecs[1], h_vecs[2], h_vecs[3], h_vecs[4], h_vecs[5], h_vecs[6], h_vecs[7], set1(IV[0]), set1(IV[1]), set1(IV[2]), set1(IV[3]), counter_low_vec, counter_high_vec, block_len_vec, block_flags_vec, }; round_fn(v, msg_vecs, 0); round_fn(v, msg_vecs, 1); round_fn(v, msg_vecs, 2); round_fn(v, msg_vecs, 3); round_fn(v, msg_vecs, 4); round_fn(v, msg_vecs, 5); round_fn(v, msg_vecs, 6); h_vecs[0] = xorv(v[0], v[8]); h_vecs[1] = xorv(v[1], v[9]); h_vecs[2] = xorv(v[2], v[10]); h_vecs[3] = xorv(v[3], v[11]); h_vecs[4] = xorv(v[4], v[12]); h_vecs[5] = xorv(v[5], v[13]); h_vecs[6] = xorv(v[6], v[14]); h_vecs[7] = xorv(v[7], v[15]); block_flags = flags; } transpose_vecs(&h_vecs[0]); transpose_vecs(&h_vecs[4]); // The first four vecs now contain the first half of each output, and the // second four vecs contain the second half of each output. storeu(h_vecs[0], &out[0 * sizeof(__m128i)]); storeu(h_vecs[4], &out[1 * sizeof(__m128i)]); storeu(h_vecs[1], &out[2 * sizeof(__m128i)]); storeu(h_vecs[5], &out[3 * sizeof(__m128i)]); storeu(h_vecs[2], &out[4 * sizeof(__m128i)]); storeu(h_vecs[6], &out[5 * sizeof(__m128i)]); storeu(h_vecs[3], &out[6 * sizeof(__m128i)]); storeu(h_vecs[7], &out[7 * sizeof(__m128i)]); } INLINE void hash_one_sse2(const uint8_t *input, size_t blocks, const uint32_t key[8], uint64_t counter, uint8_t flags, uint8_t flags_start, uint8_t flags_end, uint8_t out[BLAKE3_OUT_LEN]) { uint32_t cv[8]; memcpy(cv, key, BLAKE3_KEY_LEN); uint8_t block_flags = flags | flags_start; while (blocks > 0) { if (blocks == 1) { block_flags |= flags_end; } blake3_compress_in_place_sse2(cv, input, BLAKE3_BLOCK_LEN, counter, block_flags); input = &input[BLAKE3_BLOCK_LEN]; blocks -= 1; block_flags = flags; } memcpy(out, cv, BLAKE3_OUT_LEN); } void blake3_hash_many_sse2(const uint8_t *const *inputs, size_t num_inputs, size_t blocks, const uint32_t key[8], uint64_t counter, bool increment_counter, uint8_t flags, uint8_t flags_start, uint8_t flags_end, uint8_t *out) { while (num_inputs >= DEGREE) { blake3_hash4_sse2(inputs, blocks, key, counter, increment_counter, flags, flags_start, flags_end, out); if (increment_counter) { counter += DEGREE; } inputs += DEGREE; num_inputs -= DEGREE; out = &out[DEGREE * BLAKE3_OUT_LEN]; } while (num_inputs > 0) { hash_one_sse2(inputs[0], blocks, key, counter, flags, flags_start, flags_end, out); if (increment_counter) { counter += 1; } inputs += 1; num_inputs -= 1; out = &out[BLAKE3_OUT_LEN]; } } librecast/libs/blake3/c/blake3_sse2_x86-64_unix.S000066400000000000000000002063721502456746400216110ustar00rootroot00000000000000#if defined(__ELF__) && defined(__linux__) .section .note.GNU-stack,"",%progbits #endif #if defined(__ELF__) && defined(__CET__) && defined(__has_include) #if __has_include() #include #endif #endif #if !defined(_CET_ENDBR) #define _CET_ENDBR #endif .intel_syntax noprefix .global blake3_hash_many_sse2 .global _blake3_hash_many_sse2 .global blake3_compress_in_place_sse2 .global _blake3_compress_in_place_sse2 .global blake3_compress_xof_sse2 .global _blake3_compress_xof_sse2 #ifdef __APPLE__ .text #else .section .text #endif .p2align 6 _blake3_hash_many_sse2: blake3_hash_many_sse2: _CET_ENDBR push r15 push r14 push r13 push r12 push rbx push rbp mov rbp, rsp sub rsp, 360 and rsp, 0xFFFFFFFFFFFFFFC0 neg r9d movd xmm0, r9d pshufd xmm0, xmm0, 0x00 movdqa xmmword ptr [rsp+0x130], xmm0 movdqa xmm1, xmm0 pand xmm1, xmmword ptr [ADD0+rip] pand xmm0, xmmword ptr [ADD1+rip] movdqa xmmword ptr [rsp+0x150], xmm0 movd xmm0, r8d pshufd xmm0, xmm0, 0x00 paddd xmm0, xmm1 movdqa xmmword ptr [rsp+0x110], xmm0 pxor xmm0, xmmword ptr [CMP_MSB_MASK+rip] pxor xmm1, xmmword ptr [CMP_MSB_MASK+rip] pcmpgtd xmm1, xmm0 shr r8, 32 movd xmm2, r8d pshufd xmm2, xmm2, 0x00 psubd xmm2, xmm1 movdqa xmmword ptr [rsp+0x120], xmm2 mov rbx, qword ptr [rbp+0x50] mov r15, rdx shl r15, 6 movzx r13d, byte ptr [rbp+0x38] movzx r12d, byte ptr [rbp+0x48] cmp rsi, 4 jc 3f 2: movdqu xmm3, xmmword ptr [rcx] pshufd xmm0, xmm3, 0x00 pshufd xmm1, xmm3, 0x55 pshufd xmm2, xmm3, 0xAA pshufd xmm3, xmm3, 0xFF movdqu xmm7, xmmword ptr [rcx+0x10] pshufd xmm4, xmm7, 0x00 pshufd xmm5, xmm7, 0x55 pshufd xmm6, xmm7, 0xAA pshufd xmm7, xmm7, 0xFF mov r8, qword ptr [rdi] mov r9, qword ptr [rdi+0x8] mov r10, qword ptr [rdi+0x10] mov r11, qword ptr [rdi+0x18] movzx eax, byte ptr [rbp+0x40] or eax, r13d xor edx, edx 9: mov r14d, eax or eax, r12d add rdx, 64 cmp rdx, r15 cmovne eax, r14d movdqu xmm8, xmmword ptr [r8+rdx-0x40] movdqu xmm9, xmmword ptr [r9+rdx-0x40] movdqu xmm10, xmmword ptr [r10+rdx-0x40] movdqu xmm11, xmmword ptr [r11+rdx-0x40] movdqa xmm12, xmm8 punpckldq xmm8, xmm9 punpckhdq xmm12, xmm9 movdqa xmm14, xmm10 punpckldq xmm10, xmm11 punpckhdq xmm14, xmm11 movdqa xmm9, xmm8 punpcklqdq xmm8, xmm10 punpckhqdq xmm9, xmm10 movdqa xmm13, xmm12 punpcklqdq xmm12, xmm14 punpckhqdq xmm13, xmm14 movdqa xmmword ptr [rsp], xmm8 movdqa xmmword ptr [rsp+0x10], xmm9 movdqa xmmword ptr [rsp+0x20], xmm12 movdqa xmmword ptr [rsp+0x30], xmm13 movdqu xmm8, xmmword ptr [r8+rdx-0x30] movdqu xmm9, xmmword ptr [r9+rdx-0x30] movdqu xmm10, xmmword ptr [r10+rdx-0x30] movdqu xmm11, xmmword ptr [r11+rdx-0x30] movdqa xmm12, xmm8 punpckldq xmm8, xmm9 punpckhdq xmm12, xmm9 movdqa xmm14, xmm10 punpckldq xmm10, xmm11 punpckhdq xmm14, xmm11 movdqa xmm9, xmm8 punpcklqdq xmm8, xmm10 punpckhqdq xmm9, xmm10 movdqa xmm13, xmm12 punpcklqdq xmm12, xmm14 punpckhqdq xmm13, xmm14 movdqa xmmword ptr [rsp+0x40], xmm8 movdqa xmmword ptr [rsp+0x50], xmm9 movdqa xmmword ptr [rsp+0x60], xmm12 movdqa xmmword ptr [rsp+0x70], xmm13 movdqu xmm8, xmmword ptr [r8+rdx-0x20] movdqu xmm9, xmmword ptr [r9+rdx-0x20] movdqu xmm10, xmmword ptr [r10+rdx-0x20] movdqu xmm11, xmmword ptr [r11+rdx-0x20] movdqa xmm12, xmm8 punpckldq xmm8, xmm9 punpckhdq xmm12, xmm9 movdqa xmm14, xmm10 punpckldq xmm10, xmm11 punpckhdq xmm14, xmm11 movdqa xmm9, xmm8 punpcklqdq xmm8, xmm10 punpckhqdq xmm9, xmm10 movdqa xmm13, xmm12 punpcklqdq xmm12, xmm14 punpckhqdq xmm13, xmm14 movdqa xmmword ptr [rsp+0x80], xmm8 movdqa xmmword ptr [rsp+0x90], xmm9 movdqa xmmword ptr [rsp+0xA0], xmm12 movdqa xmmword ptr [rsp+0xB0], xmm13 movdqu xmm8, xmmword ptr [r8+rdx-0x10] movdqu xmm9, xmmword ptr [r9+rdx-0x10] movdqu xmm10, xmmword ptr [r10+rdx-0x10] movdqu xmm11, xmmword ptr [r11+rdx-0x10] movdqa xmm12, xmm8 punpckldq xmm8, xmm9 punpckhdq xmm12, xmm9 movdqa xmm14, xmm10 punpckldq xmm10, xmm11 punpckhdq xmm14, xmm11 movdqa xmm9, xmm8 punpcklqdq xmm8, xmm10 punpckhqdq xmm9, xmm10 movdqa xmm13, xmm12 punpcklqdq xmm12, xmm14 punpckhqdq xmm13, xmm14 movdqa xmmword ptr [rsp+0xC0], xmm8 movdqa xmmword ptr [rsp+0xD0], xmm9 movdqa xmmword ptr [rsp+0xE0], xmm12 movdqa xmmword ptr [rsp+0xF0], xmm13 movdqa xmm9, xmmword ptr [BLAKE3_IV_1+rip] movdqa xmm10, xmmword ptr [BLAKE3_IV_2+rip] movdqa xmm11, xmmword ptr [BLAKE3_IV_3+rip] movdqa xmm12, xmmword ptr [rsp+0x110] movdqa xmm13, xmmword ptr [rsp+0x120] movdqa xmm14, xmmword ptr [BLAKE3_BLOCK_LEN+rip] movd xmm15, eax pshufd xmm15, xmm15, 0x00 prefetcht0 [r8+rdx+0x80] prefetcht0 [r9+rdx+0x80] prefetcht0 [r10+rdx+0x80] prefetcht0 [r11+rdx+0x80] paddd xmm0, xmmword ptr [rsp] paddd xmm1, xmmword ptr [rsp+0x20] paddd xmm2, xmmword ptr [rsp+0x40] paddd xmm3, xmmword ptr [rsp+0x60] paddd xmm0, xmm4 paddd xmm1, xmm5 paddd xmm2, xmm6 paddd xmm3, xmm7 pxor xmm12, xmm0 pxor xmm13, xmm1 pxor xmm14, xmm2 pxor xmm15, xmm3 pshuflw xmm12, xmm12, 0xB1 pshufhw xmm12, xmm12, 0xB1 pshuflw xmm13, xmm13, 0xB1 pshufhw xmm13, xmm13, 0xB1 pshuflw xmm14, xmm14, 0xB1 pshufhw xmm14, xmm14, 0xB1 pshuflw xmm15, xmm15, 0xB1 pshufhw xmm15, xmm15, 0xB1 movdqa xmm8, xmmword ptr [BLAKE3_IV_0+rip] paddd xmm8, xmm12 paddd xmm9, xmm13 paddd xmm10, xmm14 paddd xmm11, xmm15 pxor xmm4, xmm8 pxor xmm5, xmm9 pxor xmm6, xmm10 pxor xmm7, xmm11 movdqa xmmword ptr [rsp+0x100], xmm8 movdqa xmm8, xmm4 psrld xmm8, 12 pslld xmm4, 20 por xmm4, xmm8 movdqa xmm8, xmm5 psrld xmm8, 12 pslld xmm5, 20 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 12 pslld xmm6, 20 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 12 pslld xmm7, 20 por xmm7, xmm8 paddd xmm0, xmmword ptr [rsp+0x10] paddd xmm1, xmmword ptr [rsp+0x30] paddd xmm2, xmmword ptr [rsp+0x50] paddd xmm3, xmmword ptr [rsp+0x70] paddd xmm0, xmm4 paddd xmm1, xmm5 paddd xmm2, xmm6 paddd xmm3, xmm7 pxor xmm12, xmm0 pxor xmm13, xmm1 pxor xmm14, xmm2 pxor xmm15, xmm3 movdqa xmm8, xmm12 psrld xmm12, 8 pslld xmm8, 24 pxor xmm12, xmm8 movdqa xmm8, xmm13 psrld xmm13, 8 pslld xmm8, 24 pxor xmm13, xmm8 movdqa xmm8, xmm14 psrld xmm14, 8 pslld xmm8, 24 pxor xmm14, xmm8 movdqa xmm8, xmm15 psrld xmm15, 8 pslld xmm8, 24 pxor xmm15, xmm8 movdqa xmm8, xmmword ptr [rsp+0x100] paddd xmm8, xmm12 paddd xmm9, xmm13 paddd xmm10, xmm14 paddd xmm11, xmm15 pxor xmm4, xmm8 pxor xmm5, xmm9 pxor xmm6, xmm10 pxor xmm7, xmm11 movdqa xmmword ptr [rsp+0x100], xmm8 movdqa xmm8, xmm4 psrld xmm8, 7 pslld xmm4, 25 por xmm4, xmm8 movdqa xmm8, xmm5 psrld xmm8, 7 pslld xmm5, 25 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 7 pslld xmm6, 25 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 7 pslld xmm7, 25 por xmm7, xmm8 paddd xmm0, xmmword ptr [rsp+0x80] paddd xmm1, xmmword ptr [rsp+0xA0] paddd xmm2, xmmword ptr [rsp+0xC0] paddd xmm3, xmmword ptr [rsp+0xE0] paddd xmm0, xmm5 paddd xmm1, xmm6 paddd xmm2, xmm7 paddd xmm3, xmm4 pxor xmm15, xmm0 pxor xmm12, xmm1 pxor xmm13, xmm2 pxor xmm14, xmm3 pshuflw xmm15, xmm15, 0xB1 pshufhw xmm15, xmm15, 0xB1 pshuflw xmm12, xmm12, 0xB1 pshufhw xmm12, xmm12, 0xB1 pshuflw xmm13, xmm13, 0xB1 pshufhw xmm13, xmm13, 0xB1 pshuflw xmm14, xmm14, 0xB1 pshufhw xmm14, xmm14, 0xB1 paddd xmm10, xmm15 paddd xmm11, xmm12 movdqa xmm8, xmmword ptr [rsp+0x100] paddd xmm8, xmm13 paddd xmm9, xmm14 pxor xmm5, xmm10 pxor xmm6, xmm11 pxor xmm7, xmm8 pxor xmm4, xmm9 movdqa xmmword ptr [rsp+0x100], xmm8 movdqa xmm8, xmm5 psrld xmm8, 12 pslld xmm5, 20 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 12 pslld xmm6, 20 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 12 pslld xmm7, 20 por xmm7, xmm8 movdqa xmm8, xmm4 psrld xmm8, 12 pslld xmm4, 20 por xmm4, xmm8 paddd xmm0, xmmword ptr [rsp+0x90] paddd xmm1, xmmword ptr [rsp+0xB0] paddd xmm2, xmmword ptr [rsp+0xD0] paddd xmm3, xmmword ptr [rsp+0xF0] paddd xmm0, xmm5 paddd xmm1, xmm6 paddd xmm2, xmm7 paddd xmm3, xmm4 pxor xmm15, xmm0 pxor xmm12, xmm1 pxor xmm13, xmm2 pxor xmm14, xmm3 movdqa xmm8, xmm15 psrld xmm15, 8 pslld xmm8, 24 pxor xmm15, xmm8 movdqa xmm8, xmm12 psrld xmm12, 8 pslld xmm8, 24 pxor xmm12, xmm8 movdqa xmm8, xmm13 psrld xmm13, 8 pslld xmm8, 24 pxor xmm13, xmm8 movdqa xmm8, xmm14 psrld xmm14, 8 pslld xmm8, 24 pxor xmm14, xmm8 paddd xmm10, xmm15 paddd xmm11, xmm12 movdqa xmm8, xmmword ptr [rsp+0x100] paddd xmm8, xmm13 paddd xmm9, xmm14 pxor xmm5, xmm10 pxor xmm6, xmm11 pxor xmm7, xmm8 pxor xmm4, xmm9 movdqa xmmword ptr [rsp+0x100], xmm8 movdqa xmm8, xmm5 psrld xmm8, 7 pslld xmm5, 25 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 7 pslld xmm6, 25 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 7 pslld xmm7, 25 por xmm7, xmm8 movdqa xmm8, xmm4 psrld xmm8, 7 pslld xmm4, 25 por xmm4, xmm8 paddd xmm0, xmmword ptr [rsp+0x20] paddd xmm1, xmmword ptr [rsp+0x30] paddd xmm2, xmmword ptr [rsp+0x70] paddd xmm3, xmmword ptr [rsp+0x40] paddd xmm0, xmm4 paddd xmm1, xmm5 paddd xmm2, xmm6 paddd xmm3, xmm7 pxor xmm12, xmm0 pxor xmm13, xmm1 pxor xmm14, xmm2 pxor xmm15, xmm3 pshuflw xmm12, xmm12, 0xB1 pshufhw xmm12, xmm12, 0xB1 pshuflw xmm13, xmm13, 0xB1 pshufhw xmm13, xmm13, 0xB1 pshuflw xmm14, xmm14, 0xB1 pshufhw xmm14, xmm14, 0xB1 pshuflw xmm15, xmm15, 0xB1 pshufhw xmm15, xmm15, 0xB1 movdqa xmm8, xmmword ptr [rsp+0x100] paddd xmm8, xmm12 paddd xmm9, xmm13 paddd xmm10, xmm14 paddd xmm11, xmm15 pxor xmm4, xmm8 pxor xmm5, xmm9 pxor xmm6, xmm10 pxor xmm7, xmm11 movdqa xmmword ptr [rsp+0x100], xmm8 movdqa xmm8, xmm4 psrld xmm8, 12 pslld xmm4, 20 por xmm4, xmm8 movdqa xmm8, xmm5 psrld xmm8, 12 pslld xmm5, 20 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 12 pslld xmm6, 20 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 12 pslld xmm7, 20 por xmm7, xmm8 paddd xmm0, xmmword ptr [rsp+0x60] paddd xmm1, xmmword ptr [rsp+0xA0] paddd xmm2, xmmword ptr [rsp] paddd xmm3, xmmword ptr [rsp+0xD0] paddd xmm0, xmm4 paddd xmm1, xmm5 paddd xmm2, xmm6 paddd xmm3, xmm7 pxor xmm12, xmm0 pxor xmm13, xmm1 pxor xmm14, xmm2 pxor xmm15, xmm3 movdqa xmm8, xmm12 psrld xmm12, 8 pslld xmm8, 24 pxor xmm12, xmm8 movdqa xmm8, xmm13 psrld xmm13, 8 pslld xmm8, 24 pxor xmm13, xmm8 movdqa xmm8, xmm14 psrld xmm14, 8 pslld xmm8, 24 pxor xmm14, xmm8 movdqa xmm8, xmm15 psrld xmm15, 8 pslld xmm8, 24 pxor xmm15, xmm8 movdqa xmm8, xmmword ptr [rsp+0x100] paddd xmm8, xmm12 paddd xmm9, xmm13 paddd xmm10, xmm14 paddd xmm11, xmm15 pxor xmm4, xmm8 pxor xmm5, xmm9 pxor xmm6, xmm10 pxor xmm7, xmm11 movdqa xmmword ptr [rsp+0x100], xmm8 movdqa xmm8, xmm4 psrld xmm8, 7 pslld xmm4, 25 por xmm4, xmm8 movdqa xmm8, xmm5 psrld xmm8, 7 pslld xmm5, 25 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 7 pslld xmm6, 25 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 7 pslld xmm7, 25 por xmm7, xmm8 paddd xmm0, xmmword ptr [rsp+0x10] paddd xmm1, xmmword ptr [rsp+0xC0] paddd xmm2, xmmword ptr [rsp+0x90] paddd xmm3, xmmword ptr [rsp+0xF0] paddd xmm0, xmm5 paddd xmm1, xmm6 paddd xmm2, xmm7 paddd xmm3, xmm4 pxor xmm15, xmm0 pxor xmm12, xmm1 pxor xmm13, xmm2 pxor xmm14, xmm3 pshuflw xmm15, xmm15, 0xB1 pshufhw xmm15, xmm15, 0xB1 pshuflw xmm12, xmm12, 0xB1 pshufhw xmm12, xmm12, 0xB1 pshuflw xmm13, xmm13, 0xB1 pshufhw xmm13, xmm13, 0xB1 pshuflw xmm14, xmm14, 0xB1 pshufhw xmm14, xmm14, 0xB1 paddd xmm10, xmm15 paddd xmm11, xmm12 movdqa xmm8, xmmword ptr [rsp+0x100] paddd xmm8, xmm13 paddd xmm9, xmm14 pxor xmm5, xmm10 pxor xmm6, xmm11 pxor xmm7, xmm8 pxor xmm4, xmm9 movdqa xmmword ptr [rsp+0x100], xmm8 movdqa xmm8, xmm5 psrld xmm8, 12 pslld xmm5, 20 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 12 pslld xmm6, 20 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 12 pslld xmm7, 20 por xmm7, xmm8 movdqa xmm8, xmm4 psrld xmm8, 12 pslld xmm4, 20 por xmm4, xmm8 paddd xmm0, xmmword ptr [rsp+0xB0] paddd xmm1, xmmword ptr [rsp+0x50] paddd xmm2, xmmword ptr [rsp+0xE0] paddd xmm3, xmmword ptr [rsp+0x80] paddd xmm0, xmm5 paddd xmm1, xmm6 paddd xmm2, xmm7 paddd xmm3, xmm4 pxor xmm15, xmm0 pxor xmm12, xmm1 pxor xmm13, xmm2 pxor xmm14, xmm3 movdqa xmm8, xmm15 psrld xmm15, 8 pslld xmm8, 24 pxor xmm15, xmm8 movdqa xmm8, xmm12 psrld xmm12, 8 pslld xmm8, 24 pxor xmm12, xmm8 movdqa xmm8, xmm13 psrld xmm13, 8 pslld xmm8, 24 pxor xmm13, xmm8 movdqa xmm8, xmm14 psrld xmm14, 8 pslld xmm8, 24 pxor xmm14, xmm8 paddd xmm10, xmm15 paddd xmm11, xmm12 movdqa xmm8, xmmword ptr [rsp+0x100] paddd xmm8, xmm13 paddd xmm9, xmm14 pxor xmm5, xmm10 pxor xmm6, xmm11 pxor xmm7, xmm8 pxor xmm4, xmm9 movdqa xmmword ptr [rsp+0x100], xmm8 movdqa xmm8, xmm5 psrld xmm8, 7 pslld xmm5, 25 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 7 pslld xmm6, 25 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 7 pslld xmm7, 25 por xmm7, xmm8 movdqa xmm8, xmm4 psrld xmm8, 7 pslld xmm4, 25 por xmm4, xmm8 paddd xmm0, xmmword ptr [rsp+0x30] paddd xmm1, xmmword ptr [rsp+0xA0] paddd xmm2, xmmword ptr [rsp+0xD0] paddd xmm3, xmmword ptr [rsp+0x70] paddd xmm0, xmm4 paddd xmm1, xmm5 paddd xmm2, xmm6 paddd xmm3, xmm7 pxor xmm12, xmm0 pxor xmm13, xmm1 pxor xmm14, xmm2 pxor xmm15, xmm3 pshuflw xmm12, xmm12, 0xB1 pshufhw xmm12, xmm12, 0xB1 pshuflw xmm13, xmm13, 0xB1 pshufhw xmm13, xmm13, 0xB1 pshuflw xmm14, xmm14, 0xB1 pshufhw xmm14, xmm14, 0xB1 pshuflw xmm15, xmm15, 0xB1 pshufhw xmm15, xmm15, 0xB1 movdqa xmm8, xmmword ptr [rsp+0x100] paddd xmm8, xmm12 paddd xmm9, xmm13 paddd xmm10, xmm14 paddd xmm11, xmm15 pxor xmm4, xmm8 pxor xmm5, xmm9 pxor xmm6, xmm10 pxor xmm7, xmm11 movdqa xmmword ptr [rsp+0x100], xmm8 movdqa xmm8, xmm4 psrld xmm8, 12 pslld xmm4, 20 por xmm4, xmm8 movdqa xmm8, xmm5 psrld xmm8, 12 pslld xmm5, 20 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 12 pslld xmm6, 20 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 12 pslld xmm7, 20 por xmm7, xmm8 paddd xmm0, xmmword ptr [rsp+0x40] paddd xmm1, xmmword ptr [rsp+0xC0] paddd xmm2, xmmword ptr [rsp+0x20] paddd xmm3, xmmword ptr [rsp+0xE0] paddd xmm0, xmm4 paddd xmm1, xmm5 paddd xmm2, xmm6 paddd xmm3, xmm7 pxor xmm12, xmm0 pxor xmm13, xmm1 pxor xmm14, xmm2 pxor xmm15, xmm3 movdqa xmm8, xmm12 psrld xmm12, 8 pslld xmm8, 24 pxor xmm12, xmm8 movdqa xmm8, xmm13 psrld xmm13, 8 pslld xmm8, 24 pxor xmm13, xmm8 movdqa xmm8, xmm14 psrld xmm14, 8 pslld xmm8, 24 pxor xmm14, xmm8 movdqa xmm8, xmm15 psrld xmm15, 8 pslld xmm8, 24 pxor xmm15, xmm8 movdqa xmm8, xmmword ptr [rsp+0x100] paddd xmm8, xmm12 paddd xmm9, xmm13 paddd xmm10, xmm14 paddd xmm11, xmm15 pxor xmm4, xmm8 pxor xmm5, xmm9 pxor xmm6, xmm10 pxor xmm7, xmm11 movdqa xmmword ptr [rsp+0x100], xmm8 movdqa xmm8, xmm4 psrld xmm8, 7 pslld xmm4, 25 por xmm4, xmm8 movdqa xmm8, xmm5 psrld xmm8, 7 pslld xmm5, 25 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 7 pslld xmm6, 25 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 7 pslld xmm7, 25 por xmm7, xmm8 paddd xmm0, xmmword ptr [rsp+0x60] paddd xmm1, xmmword ptr [rsp+0x90] paddd xmm2, xmmword ptr [rsp+0xB0] paddd xmm3, xmmword ptr [rsp+0x80] paddd xmm0, xmm5 paddd xmm1, xmm6 paddd xmm2, xmm7 paddd xmm3, xmm4 pxor xmm15, xmm0 pxor xmm12, xmm1 pxor xmm13, xmm2 pxor xmm14, xmm3 pshuflw xmm15, xmm15, 0xB1 pshufhw xmm15, xmm15, 0xB1 pshuflw xmm12, xmm12, 0xB1 pshufhw xmm12, xmm12, 0xB1 pshuflw xmm13, xmm13, 0xB1 pshufhw xmm13, xmm13, 0xB1 pshuflw xmm14, xmm14, 0xB1 pshufhw xmm14, xmm14, 0xB1 paddd xmm10, xmm15 paddd xmm11, xmm12 movdqa xmm8, xmmword ptr [rsp+0x100] paddd xmm8, xmm13 paddd xmm9, xmm14 pxor xmm5, xmm10 pxor xmm6, xmm11 pxor xmm7, xmm8 pxor xmm4, xmm9 movdqa xmmword ptr [rsp+0x100], xmm8 movdqa xmm8, xmm5 psrld xmm8, 12 pslld xmm5, 20 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 12 pslld xmm6, 20 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 12 pslld xmm7, 20 por xmm7, xmm8 movdqa xmm8, xmm4 psrld xmm8, 12 pslld xmm4, 20 por xmm4, xmm8 paddd xmm0, xmmword ptr [rsp+0x50] paddd xmm1, xmmword ptr [rsp] paddd xmm2, xmmword ptr [rsp+0xF0] paddd xmm3, xmmword ptr [rsp+0x10] paddd xmm0, xmm5 paddd xmm1, xmm6 paddd xmm2, xmm7 paddd xmm3, xmm4 pxor xmm15, xmm0 pxor xmm12, xmm1 pxor xmm13, xmm2 pxor xmm14, xmm3 movdqa xmm8, xmm15 psrld xmm15, 8 pslld xmm8, 24 pxor xmm15, xmm8 movdqa xmm8, xmm12 psrld xmm12, 8 pslld xmm8, 24 pxor xmm12, xmm8 movdqa xmm8, xmm13 psrld xmm13, 8 pslld xmm8, 24 pxor xmm13, xmm8 movdqa xmm8, xmm14 psrld xmm14, 8 pslld xmm8, 24 pxor xmm14, xmm8 paddd xmm10, xmm15 paddd xmm11, xmm12 movdqa xmm8, xmmword ptr [rsp+0x100] paddd xmm8, xmm13 paddd xmm9, xmm14 pxor xmm5, xmm10 pxor xmm6, xmm11 pxor xmm7, xmm8 pxor xmm4, xmm9 movdqa xmmword ptr [rsp+0x100], xmm8 movdqa xmm8, xmm5 psrld xmm8, 7 pslld xmm5, 25 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 7 pslld xmm6, 25 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 7 pslld xmm7, 25 por xmm7, xmm8 movdqa xmm8, xmm4 psrld xmm8, 7 pslld xmm4, 25 por xmm4, xmm8 paddd xmm0, xmmword ptr [rsp+0xA0] paddd xmm1, xmmword ptr [rsp+0xC0] paddd xmm2, xmmword ptr [rsp+0xE0] paddd xmm3, xmmword ptr [rsp+0xD0] paddd xmm0, xmm4 paddd xmm1, xmm5 paddd xmm2, xmm6 paddd xmm3, xmm7 pxor xmm12, xmm0 pxor xmm13, xmm1 pxor xmm14, xmm2 pxor xmm15, xmm3 pshuflw xmm12, xmm12, 0xB1 pshufhw xmm12, xmm12, 0xB1 pshuflw xmm13, xmm13, 0xB1 pshufhw xmm13, xmm13, 0xB1 pshuflw xmm14, xmm14, 0xB1 pshufhw xmm14, xmm14, 0xB1 pshuflw xmm15, xmm15, 0xB1 pshufhw xmm15, xmm15, 0xB1 movdqa xmm8, xmmword ptr [rsp+0x100] paddd xmm8, xmm12 paddd xmm9, xmm13 paddd xmm10, xmm14 paddd xmm11, xmm15 pxor xmm4, xmm8 pxor xmm5, xmm9 pxor xmm6, xmm10 pxor xmm7, xmm11 movdqa xmmword ptr [rsp+0x100], xmm8 movdqa xmm8, xmm4 psrld xmm8, 12 pslld xmm4, 20 por xmm4, xmm8 movdqa xmm8, xmm5 psrld xmm8, 12 pslld xmm5, 20 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 12 pslld xmm6, 20 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 12 pslld xmm7, 20 por xmm7, xmm8 paddd xmm0, xmmword ptr [rsp+0x70] paddd xmm1, xmmword ptr [rsp+0x90] paddd xmm2, xmmword ptr [rsp+0x30] paddd xmm3, xmmword ptr [rsp+0xF0] paddd xmm0, xmm4 paddd xmm1, xmm5 paddd xmm2, xmm6 paddd xmm3, xmm7 pxor xmm12, xmm0 pxor xmm13, xmm1 pxor xmm14, xmm2 pxor xmm15, xmm3 movdqa xmm8, xmm12 psrld xmm12, 8 pslld xmm8, 24 pxor xmm12, xmm8 movdqa xmm8, xmm13 psrld xmm13, 8 pslld xmm8, 24 pxor xmm13, xmm8 movdqa xmm8, xmm14 psrld xmm14, 8 pslld xmm8, 24 pxor xmm14, xmm8 movdqa xmm8, xmm15 psrld xmm15, 8 pslld xmm8, 24 pxor xmm15, xmm8 movdqa xmm8, xmmword ptr [rsp+0x100] paddd xmm8, xmm12 paddd xmm9, xmm13 paddd xmm10, xmm14 paddd xmm11, xmm15 pxor xmm4, xmm8 pxor xmm5, xmm9 pxor xmm6, xmm10 pxor xmm7, xmm11 movdqa xmmword ptr [rsp+0x100], xmm8 movdqa xmm8, xmm4 psrld xmm8, 7 pslld xmm4, 25 por xmm4, xmm8 movdqa xmm8, xmm5 psrld xmm8, 7 pslld xmm5, 25 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 7 pslld xmm6, 25 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 7 pslld xmm7, 25 por xmm7, xmm8 paddd xmm0, xmmword ptr [rsp+0x40] paddd xmm1, xmmword ptr [rsp+0xB0] paddd xmm2, xmmword ptr [rsp+0x50] paddd xmm3, xmmword ptr [rsp+0x10] paddd xmm0, xmm5 paddd xmm1, xmm6 paddd xmm2, xmm7 paddd xmm3, xmm4 pxor xmm15, xmm0 pxor xmm12, xmm1 pxor xmm13, xmm2 pxor xmm14, xmm3 pshuflw xmm15, xmm15, 0xB1 pshufhw xmm15, xmm15, 0xB1 pshuflw xmm12, xmm12, 0xB1 pshufhw xmm12, xmm12, 0xB1 pshuflw xmm13, xmm13, 0xB1 pshufhw xmm13, xmm13, 0xB1 pshuflw xmm14, xmm14, 0xB1 pshufhw xmm14, xmm14, 0xB1 paddd xmm10, xmm15 paddd xmm11, xmm12 movdqa xmm8, xmmword ptr [rsp+0x100] paddd xmm8, xmm13 paddd xmm9, xmm14 pxor xmm5, xmm10 pxor xmm6, xmm11 pxor xmm7, xmm8 pxor xmm4, xmm9 movdqa xmmword ptr [rsp+0x100], xmm8 movdqa xmm8, xmm5 psrld xmm8, 12 pslld xmm5, 20 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 12 pslld xmm6, 20 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 12 pslld xmm7, 20 por xmm7, xmm8 movdqa xmm8, xmm4 psrld xmm8, 12 pslld xmm4, 20 por xmm4, xmm8 paddd xmm0, xmmword ptr [rsp] paddd xmm1, xmmword ptr [rsp+0x20] paddd xmm2, xmmword ptr [rsp+0x80] paddd xmm3, xmmword ptr [rsp+0x60] paddd xmm0, xmm5 paddd xmm1, xmm6 paddd xmm2, xmm7 paddd xmm3, xmm4 pxor xmm15, xmm0 pxor xmm12, xmm1 pxor xmm13, xmm2 pxor xmm14, xmm3 movdqa xmm8, xmm15 psrld xmm15, 8 pslld xmm8, 24 pxor xmm15, xmm8 movdqa xmm8, xmm12 psrld xmm12, 8 pslld xmm8, 24 pxor xmm12, xmm8 movdqa xmm8, xmm13 psrld xmm13, 8 pslld xmm8, 24 pxor xmm13, xmm8 movdqa xmm8, xmm14 psrld xmm14, 8 pslld xmm8, 24 pxor xmm14, xmm8 paddd xmm10, xmm15 paddd xmm11, xmm12 movdqa xmm8, xmmword ptr [rsp+0x100] paddd xmm8, xmm13 paddd xmm9, xmm14 pxor xmm5, xmm10 pxor xmm6, xmm11 pxor xmm7, xmm8 pxor xmm4, xmm9 movdqa xmmword ptr [rsp+0x100], xmm8 movdqa xmm8, xmm5 psrld xmm8, 7 pslld xmm5, 25 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 7 pslld xmm6, 25 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 7 pslld xmm7, 25 por xmm7, xmm8 movdqa xmm8, xmm4 psrld xmm8, 7 pslld xmm4, 25 por xmm4, xmm8 paddd xmm0, xmmword ptr [rsp+0xC0] paddd xmm1, xmmword ptr [rsp+0x90] paddd xmm2, xmmword ptr [rsp+0xF0] paddd xmm3, xmmword ptr [rsp+0xE0] paddd xmm0, xmm4 paddd xmm1, xmm5 paddd xmm2, xmm6 paddd xmm3, xmm7 pxor xmm12, xmm0 pxor xmm13, xmm1 pxor xmm14, xmm2 pxor xmm15, xmm3 pshuflw xmm12, xmm12, 0xB1 pshufhw xmm12, xmm12, 0xB1 pshuflw xmm13, xmm13, 0xB1 pshufhw xmm13, xmm13, 0xB1 pshuflw xmm14, xmm14, 0xB1 pshufhw xmm14, xmm14, 0xB1 pshuflw xmm15, xmm15, 0xB1 pshufhw xmm15, xmm15, 0xB1 movdqa xmm8, xmmword ptr [rsp+0x100] paddd xmm8, xmm12 paddd xmm9, xmm13 paddd xmm10, xmm14 paddd xmm11, xmm15 pxor xmm4, xmm8 pxor xmm5, xmm9 pxor xmm6, xmm10 pxor xmm7, xmm11 movdqa xmmword ptr [rsp+0x100], xmm8 movdqa xmm8, xmm4 psrld xmm8, 12 pslld xmm4, 20 por xmm4, xmm8 movdqa xmm8, xmm5 psrld xmm8, 12 pslld xmm5, 20 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 12 pslld xmm6, 20 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 12 pslld xmm7, 20 por xmm7, xmm8 paddd xmm0, xmmword ptr [rsp+0xD0] paddd xmm1, xmmword ptr [rsp+0xB0] paddd xmm2, xmmword ptr [rsp+0xA0] paddd xmm3, xmmword ptr [rsp+0x80] paddd xmm0, xmm4 paddd xmm1, xmm5 paddd xmm2, xmm6 paddd xmm3, xmm7 pxor xmm12, xmm0 pxor xmm13, xmm1 pxor xmm14, xmm2 pxor xmm15, xmm3 movdqa xmm8, xmm12 psrld xmm12, 8 pslld xmm8, 24 pxor xmm12, xmm8 movdqa xmm8, xmm13 psrld xmm13, 8 pslld xmm8, 24 pxor xmm13, xmm8 movdqa xmm8, xmm14 psrld xmm14, 8 pslld xmm8, 24 pxor xmm14, xmm8 movdqa xmm8, xmm15 psrld xmm15, 8 pslld xmm8, 24 pxor xmm15, xmm8 movdqa xmm8, xmmword ptr [rsp+0x100] paddd xmm8, xmm12 paddd xmm9, xmm13 paddd xmm10, xmm14 paddd xmm11, xmm15 pxor xmm4, xmm8 pxor xmm5, xmm9 pxor xmm6, xmm10 pxor xmm7, xmm11 movdqa xmmword ptr [rsp+0x100], xmm8 movdqa xmm8, xmm4 psrld xmm8, 7 pslld xmm4, 25 por xmm4, xmm8 movdqa xmm8, xmm5 psrld xmm8, 7 pslld xmm5, 25 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 7 pslld xmm6, 25 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 7 pslld xmm7, 25 por xmm7, xmm8 paddd xmm0, xmmword ptr [rsp+0x70] paddd xmm1, xmmword ptr [rsp+0x50] paddd xmm2, xmmword ptr [rsp] paddd xmm3, xmmword ptr [rsp+0x60] paddd xmm0, xmm5 paddd xmm1, xmm6 paddd xmm2, xmm7 paddd xmm3, xmm4 pxor xmm15, xmm0 pxor xmm12, xmm1 pxor xmm13, xmm2 pxor xmm14, xmm3 pshuflw xmm15, xmm15, 0xB1 pshufhw xmm15, xmm15, 0xB1 pshuflw xmm12, xmm12, 0xB1 pshufhw xmm12, xmm12, 0xB1 pshuflw xmm13, xmm13, 0xB1 pshufhw xmm13, xmm13, 0xB1 pshuflw xmm14, xmm14, 0xB1 pshufhw xmm14, xmm14, 0xB1 paddd xmm10, xmm15 paddd xmm11, xmm12 movdqa xmm8, xmmword ptr [rsp+0x100] paddd xmm8, xmm13 paddd xmm9, xmm14 pxor xmm5, xmm10 pxor xmm6, xmm11 pxor xmm7, xmm8 pxor xmm4, xmm9 movdqa xmmword ptr [rsp+0x100], xmm8 movdqa xmm8, xmm5 psrld xmm8, 12 pslld xmm5, 20 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 12 pslld xmm6, 20 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 12 pslld xmm7, 20 por xmm7, xmm8 movdqa xmm8, xmm4 psrld xmm8, 12 pslld xmm4, 20 por xmm4, xmm8 paddd xmm0, xmmword ptr [rsp+0x20] paddd xmm1, xmmword ptr [rsp+0x30] paddd xmm2, xmmword ptr [rsp+0x10] paddd xmm3, xmmword ptr [rsp+0x40] paddd xmm0, xmm5 paddd xmm1, xmm6 paddd xmm2, xmm7 paddd xmm3, xmm4 pxor xmm15, xmm0 pxor xmm12, xmm1 pxor xmm13, xmm2 pxor xmm14, xmm3 movdqa xmm8, xmm15 psrld xmm15, 8 pslld xmm8, 24 pxor xmm15, xmm8 movdqa xmm8, xmm12 psrld xmm12, 8 pslld xmm8, 24 pxor xmm12, xmm8 movdqa xmm8, xmm13 psrld xmm13, 8 pslld xmm8, 24 pxor xmm13, xmm8 movdqa xmm8, xmm14 psrld xmm14, 8 pslld xmm8, 24 pxor xmm14, xmm8 paddd xmm10, xmm15 paddd xmm11, xmm12 movdqa xmm8, xmmword ptr [rsp+0x100] paddd xmm8, xmm13 paddd xmm9, xmm14 pxor xmm5, xmm10 pxor xmm6, xmm11 pxor xmm7, xmm8 pxor xmm4, xmm9 movdqa xmmword ptr [rsp+0x100], xmm8 movdqa xmm8, xmm5 psrld xmm8, 7 pslld xmm5, 25 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 7 pslld xmm6, 25 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 7 pslld xmm7, 25 por xmm7, xmm8 movdqa xmm8, xmm4 psrld xmm8, 7 pslld xmm4, 25 por xmm4, xmm8 paddd xmm0, xmmword ptr [rsp+0x90] paddd xmm1, xmmword ptr [rsp+0xB0] paddd xmm2, xmmword ptr [rsp+0x80] paddd xmm3, xmmword ptr [rsp+0xF0] paddd xmm0, xmm4 paddd xmm1, xmm5 paddd xmm2, xmm6 paddd xmm3, xmm7 pxor xmm12, xmm0 pxor xmm13, xmm1 pxor xmm14, xmm2 pxor xmm15, xmm3 pshuflw xmm12, xmm12, 0xB1 pshufhw xmm12, xmm12, 0xB1 pshuflw xmm13, xmm13, 0xB1 pshufhw xmm13, xmm13, 0xB1 pshuflw xmm14, xmm14, 0xB1 pshufhw xmm14, xmm14, 0xB1 pshuflw xmm15, xmm15, 0xB1 pshufhw xmm15, xmm15, 0xB1 movdqa xmm8, xmmword ptr [rsp+0x100] paddd xmm8, xmm12 paddd xmm9, xmm13 paddd xmm10, xmm14 paddd xmm11, xmm15 pxor xmm4, xmm8 pxor xmm5, xmm9 pxor xmm6, xmm10 pxor xmm7, xmm11 movdqa xmmword ptr [rsp+0x100], xmm8 movdqa xmm8, xmm4 psrld xmm8, 12 pslld xmm4, 20 por xmm4, xmm8 movdqa xmm8, xmm5 psrld xmm8, 12 pslld xmm5, 20 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 12 pslld xmm6, 20 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 12 pslld xmm7, 20 por xmm7, xmm8 paddd xmm0, xmmword ptr [rsp+0xE0] paddd xmm1, xmmword ptr [rsp+0x50] paddd xmm2, xmmword ptr [rsp+0xC0] paddd xmm3, xmmword ptr [rsp+0x10] paddd xmm0, xmm4 paddd xmm1, xmm5 paddd xmm2, xmm6 paddd xmm3, xmm7 pxor xmm12, xmm0 pxor xmm13, xmm1 pxor xmm14, xmm2 pxor xmm15, xmm3 movdqa xmm8, xmm12 psrld xmm12, 8 pslld xmm8, 24 pxor xmm12, xmm8 movdqa xmm8, xmm13 psrld xmm13, 8 pslld xmm8, 24 pxor xmm13, xmm8 movdqa xmm8, xmm14 psrld xmm14, 8 pslld xmm8, 24 pxor xmm14, xmm8 movdqa xmm8, xmm15 psrld xmm15, 8 pslld xmm8, 24 pxor xmm15, xmm8 movdqa xmm8, xmmword ptr [rsp+0x100] paddd xmm8, xmm12 paddd xmm9, xmm13 paddd xmm10, xmm14 paddd xmm11, xmm15 pxor xmm4, xmm8 pxor xmm5, xmm9 pxor xmm6, xmm10 pxor xmm7, xmm11 movdqa xmmword ptr [rsp+0x100], xmm8 movdqa xmm8, xmm4 psrld xmm8, 7 pslld xmm4, 25 por xmm4, xmm8 movdqa xmm8, xmm5 psrld xmm8, 7 pslld xmm5, 25 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 7 pslld xmm6, 25 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 7 pslld xmm7, 25 por xmm7, xmm8 paddd xmm0, xmmword ptr [rsp+0xD0] paddd xmm1, xmmword ptr [rsp] paddd xmm2, xmmword ptr [rsp+0x20] paddd xmm3, xmmword ptr [rsp+0x40] paddd xmm0, xmm5 paddd xmm1, xmm6 paddd xmm2, xmm7 paddd xmm3, xmm4 pxor xmm15, xmm0 pxor xmm12, xmm1 pxor xmm13, xmm2 pxor xmm14, xmm3 pshuflw xmm15, xmm15, 0xB1 pshufhw xmm15, xmm15, 0xB1 pshuflw xmm12, xmm12, 0xB1 pshufhw xmm12, xmm12, 0xB1 pshuflw xmm13, xmm13, 0xB1 pshufhw xmm13, xmm13, 0xB1 pshuflw xmm14, xmm14, 0xB1 pshufhw xmm14, xmm14, 0xB1 paddd xmm10, xmm15 paddd xmm11, xmm12 movdqa xmm8, xmmword ptr [rsp+0x100] paddd xmm8, xmm13 paddd xmm9, xmm14 pxor xmm5, xmm10 pxor xmm6, xmm11 pxor xmm7, xmm8 pxor xmm4, xmm9 movdqa xmmword ptr [rsp+0x100], xmm8 movdqa xmm8, xmm5 psrld xmm8, 12 pslld xmm5, 20 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 12 pslld xmm6, 20 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 12 pslld xmm7, 20 por xmm7, xmm8 movdqa xmm8, xmm4 psrld xmm8, 12 pslld xmm4, 20 por xmm4, xmm8 paddd xmm0, xmmword ptr [rsp+0x30] paddd xmm1, xmmword ptr [rsp+0xA0] paddd xmm2, xmmword ptr [rsp+0x60] paddd xmm3, xmmword ptr [rsp+0x70] paddd xmm0, xmm5 paddd xmm1, xmm6 paddd xmm2, xmm7 paddd xmm3, xmm4 pxor xmm15, xmm0 pxor xmm12, xmm1 pxor xmm13, xmm2 pxor xmm14, xmm3 movdqa xmm8, xmm15 psrld xmm15, 8 pslld xmm8, 24 pxor xmm15, xmm8 movdqa xmm8, xmm12 psrld xmm12, 8 pslld xmm8, 24 pxor xmm12, xmm8 movdqa xmm8, xmm13 psrld xmm13, 8 pslld xmm8, 24 pxor xmm13, xmm8 movdqa xmm8, xmm14 psrld xmm14, 8 pslld xmm8, 24 pxor xmm14, xmm8 paddd xmm10, xmm15 paddd xmm11, xmm12 movdqa xmm8, xmmword ptr [rsp+0x100] paddd xmm8, xmm13 paddd xmm9, xmm14 pxor xmm5, xmm10 pxor xmm6, xmm11 pxor xmm7, xmm8 pxor xmm4, xmm9 movdqa xmmword ptr [rsp+0x100], xmm8 movdqa xmm8, xmm5 psrld xmm8, 7 pslld xmm5, 25 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 7 pslld xmm6, 25 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 7 pslld xmm7, 25 por xmm7, xmm8 movdqa xmm8, xmm4 psrld xmm8, 7 pslld xmm4, 25 por xmm4, xmm8 paddd xmm0, xmmword ptr [rsp+0xB0] paddd xmm1, xmmword ptr [rsp+0x50] paddd xmm2, xmmword ptr [rsp+0x10] paddd xmm3, xmmword ptr [rsp+0x80] paddd xmm0, xmm4 paddd xmm1, xmm5 paddd xmm2, xmm6 paddd xmm3, xmm7 pxor xmm12, xmm0 pxor xmm13, xmm1 pxor xmm14, xmm2 pxor xmm15, xmm3 pshuflw xmm12, xmm12, 0xB1 pshufhw xmm12, xmm12, 0xB1 pshuflw xmm13, xmm13, 0xB1 pshufhw xmm13, xmm13, 0xB1 pshuflw xmm14, xmm14, 0xB1 pshufhw xmm14, xmm14, 0xB1 pshuflw xmm15, xmm15, 0xB1 pshufhw xmm15, xmm15, 0xB1 movdqa xmm8, xmmword ptr [rsp+0x100] paddd xmm8, xmm12 paddd xmm9, xmm13 paddd xmm10, xmm14 paddd xmm11, xmm15 pxor xmm4, xmm8 pxor xmm5, xmm9 pxor xmm6, xmm10 pxor xmm7, xmm11 movdqa xmmword ptr [rsp+0x100], xmm8 movdqa xmm8, xmm4 psrld xmm8, 12 pslld xmm4, 20 por xmm4, xmm8 movdqa xmm8, xmm5 psrld xmm8, 12 pslld xmm5, 20 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 12 pslld xmm6, 20 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 12 pslld xmm7, 20 por xmm7, xmm8 paddd xmm0, xmmword ptr [rsp+0xF0] paddd xmm1, xmmword ptr [rsp] paddd xmm2, xmmword ptr [rsp+0x90] paddd xmm3, xmmword ptr [rsp+0x60] paddd xmm0, xmm4 paddd xmm1, xmm5 paddd xmm2, xmm6 paddd xmm3, xmm7 pxor xmm12, xmm0 pxor xmm13, xmm1 pxor xmm14, xmm2 pxor xmm15, xmm3 movdqa xmm8, xmm12 psrld xmm12, 8 pslld xmm8, 24 pxor xmm12, xmm8 movdqa xmm8, xmm13 psrld xmm13, 8 pslld xmm8, 24 pxor xmm13, xmm8 movdqa xmm8, xmm14 psrld xmm14, 8 pslld xmm8, 24 pxor xmm14, xmm8 movdqa xmm8, xmm15 psrld xmm15, 8 pslld xmm8, 24 pxor xmm15, xmm8 movdqa xmm8, xmmword ptr [rsp+0x100] paddd xmm8, xmm12 paddd xmm9, xmm13 paddd xmm10, xmm14 paddd xmm11, xmm15 pxor xmm4, xmm8 pxor xmm5, xmm9 pxor xmm6, xmm10 pxor xmm7, xmm11 movdqa xmmword ptr [rsp+0x100], xmm8 movdqa xmm8, xmm4 psrld xmm8, 7 pslld xmm4, 25 por xmm4, xmm8 movdqa xmm8, xmm5 psrld xmm8, 7 pslld xmm5, 25 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 7 pslld xmm6, 25 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 7 pslld xmm7, 25 por xmm7, xmm8 paddd xmm0, xmmword ptr [rsp+0xE0] paddd xmm1, xmmword ptr [rsp+0x20] paddd xmm2, xmmword ptr [rsp+0x30] paddd xmm3, xmmword ptr [rsp+0x70] paddd xmm0, xmm5 paddd xmm1, xmm6 paddd xmm2, xmm7 paddd xmm3, xmm4 pxor xmm15, xmm0 pxor xmm12, xmm1 pxor xmm13, xmm2 pxor xmm14, xmm3 pshuflw xmm15, xmm15, 0xB1 pshufhw xmm15, xmm15, 0xB1 pshuflw xmm12, xmm12, 0xB1 pshufhw xmm12, xmm12, 0xB1 pshuflw xmm13, xmm13, 0xB1 pshufhw xmm13, xmm13, 0xB1 pshuflw xmm14, xmm14, 0xB1 pshufhw xmm14, xmm14, 0xB1 paddd xmm10, xmm15 paddd xmm11, xmm12 movdqa xmm8, xmmword ptr [rsp+0x100] paddd xmm8, xmm13 paddd xmm9, xmm14 pxor xmm5, xmm10 pxor xmm6, xmm11 pxor xmm7, xmm8 pxor xmm4, xmm9 movdqa xmmword ptr [rsp+0x100], xmm8 movdqa xmm8, xmm5 psrld xmm8, 12 pslld xmm5, 20 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 12 pslld xmm6, 20 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 12 pslld xmm7, 20 por xmm7, xmm8 movdqa xmm8, xmm4 psrld xmm8, 12 pslld xmm4, 20 por xmm4, xmm8 paddd xmm0, xmmword ptr [rsp+0xA0] paddd xmm1, xmmword ptr [rsp+0xC0] paddd xmm2, xmmword ptr [rsp+0x40] paddd xmm3, xmmword ptr [rsp+0xD0] paddd xmm0, xmm5 paddd xmm1, xmm6 paddd xmm2, xmm7 paddd xmm3, xmm4 pxor xmm15, xmm0 pxor xmm12, xmm1 pxor xmm13, xmm2 pxor xmm14, xmm3 movdqa xmm8, xmm15 psrld xmm15, 8 pslld xmm8, 24 pxor xmm15, xmm8 movdqa xmm8, xmm12 psrld xmm12, 8 pslld xmm8, 24 pxor xmm12, xmm8 movdqa xmm8, xmm13 psrld xmm13, 8 pslld xmm8, 24 pxor xmm13, xmm8 movdqa xmm8, xmm14 psrld xmm14, 8 pslld xmm8, 24 pxor xmm14, xmm8 paddd xmm10, xmm15 paddd xmm11, xmm12 movdqa xmm8, xmmword ptr [rsp+0x100] paddd xmm8, xmm13 paddd xmm9, xmm14 pxor xmm5, xmm10 pxor xmm6, xmm11 pxor xmm7, xmm8 pxor xmm4, xmm9 pxor xmm0, xmm8 pxor xmm1, xmm9 pxor xmm2, xmm10 pxor xmm3, xmm11 movdqa xmm8, xmm5 psrld xmm8, 7 pslld xmm5, 25 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 7 pslld xmm6, 25 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 7 pslld xmm7, 25 por xmm7, xmm8 movdqa xmm8, xmm4 psrld xmm8, 7 pslld xmm4, 25 por xmm4, xmm8 pxor xmm4, xmm12 pxor xmm5, xmm13 pxor xmm6, xmm14 pxor xmm7, xmm15 mov eax, r13d jne 9b movdqa xmm9, xmm0 punpckldq xmm0, xmm1 punpckhdq xmm9, xmm1 movdqa xmm11, xmm2 punpckldq xmm2, xmm3 punpckhdq xmm11, xmm3 movdqa xmm1, xmm0 punpcklqdq xmm0, xmm2 punpckhqdq xmm1, xmm2 movdqa xmm3, xmm9 punpcklqdq xmm9, xmm11 punpckhqdq xmm3, xmm11 movdqu xmmword ptr [rbx], xmm0 movdqu xmmword ptr [rbx+0x20], xmm1 movdqu xmmword ptr [rbx+0x40], xmm9 movdqu xmmword ptr [rbx+0x60], xmm3 movdqa xmm9, xmm4 punpckldq xmm4, xmm5 punpckhdq xmm9, xmm5 movdqa xmm11, xmm6 punpckldq xmm6, xmm7 punpckhdq xmm11, xmm7 movdqa xmm5, xmm4 punpcklqdq xmm4, xmm6 punpckhqdq xmm5, xmm6 movdqa xmm7, xmm9 punpcklqdq xmm9, xmm11 punpckhqdq xmm7, xmm11 movdqu xmmword ptr [rbx+0x10], xmm4 movdqu xmmword ptr [rbx+0x30], xmm5 movdqu xmmword ptr [rbx+0x50], xmm9 movdqu xmmword ptr [rbx+0x70], xmm7 movdqa xmm1, xmmword ptr [rsp+0x110] movdqa xmm0, xmm1 paddd xmm1, xmmword ptr [rsp+0x150] movdqa xmmword ptr [rsp+0x110], xmm1 pxor xmm0, xmmword ptr [CMP_MSB_MASK+rip] pxor xmm1, xmmword ptr [CMP_MSB_MASK+rip] pcmpgtd xmm0, xmm1 movdqa xmm1, xmmword ptr [rsp+0x120] psubd xmm1, xmm0 movdqa xmmword ptr [rsp+0x120], xmm1 add rbx, 128 add rdi, 32 sub rsi, 4 cmp rsi, 4 jnc 2b test rsi, rsi jnz 3f 4: mov rsp, rbp pop rbp pop rbx pop r12 pop r13 pop r14 pop r15 ret .p2align 5 3: test esi, 0x2 je 3f movups xmm0, xmmword ptr [rcx] movups xmm1, xmmword ptr [rcx+0x10] movaps xmm8, xmm0 movaps xmm9, xmm1 movd xmm13, dword ptr [rsp+0x110] movd xmm14, dword ptr [rsp+0x120] punpckldq xmm13, xmm14 movaps xmmword ptr [rsp], xmm13 movd xmm14, dword ptr [rsp+0x114] movd xmm13, dword ptr [rsp+0x124] punpckldq xmm14, xmm13 movaps xmmword ptr [rsp+0x10], xmm14 mov r8, qword ptr [rdi] mov r9, qword ptr [rdi+0x8] movzx eax, byte ptr [rbp+0x40] or eax, r13d xor edx, edx 2: mov r14d, eax or eax, r12d add rdx, 64 cmp rdx, r15 cmovne eax, r14d movaps xmm2, xmmword ptr [BLAKE3_IV+rip] movaps xmm10, xmm2 movups xmm4, xmmword ptr [r8+rdx-0x40] movups xmm5, xmmword ptr [r8+rdx-0x30] movaps xmm3, xmm4 shufps xmm4, xmm5, 136 shufps xmm3, xmm5, 221 movaps xmm5, xmm3 movups xmm6, xmmword ptr [r8+rdx-0x20] movups xmm7, xmmword ptr [r8+rdx-0x10] movaps xmm3, xmm6 shufps xmm6, xmm7, 136 pshufd xmm6, xmm6, 0x93 shufps xmm3, xmm7, 221 pshufd xmm7, xmm3, 0x93 movups xmm12, xmmword ptr [r9+rdx-0x40] movups xmm13, xmmword ptr [r9+rdx-0x30] movaps xmm11, xmm12 shufps xmm12, xmm13, 136 shufps xmm11, xmm13, 221 movaps xmm13, xmm11 movups xmm14, xmmword ptr [r9+rdx-0x20] movups xmm15, xmmword ptr [r9+rdx-0x10] movaps xmm11, xmm14 shufps xmm14, xmm15, 136 pshufd xmm14, xmm14, 0x93 shufps xmm11, xmm15, 221 pshufd xmm15, xmm11, 0x93 shl rax, 0x20 or rax, 0x40 movq xmm3, rax movdqa xmmword ptr [rsp+0x20], xmm3 movaps xmm3, xmmword ptr [rsp] movaps xmm11, xmmword ptr [rsp+0x10] punpcklqdq xmm3, xmmword ptr [rsp+0x20] punpcklqdq xmm11, xmmword ptr [rsp+0x20] mov al, 7 9: paddd xmm0, xmm4 paddd xmm8, xmm12 movaps xmmword ptr [rsp+0x20], xmm4 movaps xmmword ptr [rsp+0x30], xmm12 paddd xmm0, xmm1 paddd xmm8, xmm9 pxor xmm3, xmm0 pxor xmm11, xmm8 pshuflw xmm3, xmm3, 0xB1 pshufhw xmm3, xmm3, 0xB1 pshuflw xmm11, xmm11, 0xB1 pshufhw xmm11, xmm11, 0xB1 paddd xmm2, xmm3 paddd xmm10, xmm11 pxor xmm1, xmm2 pxor xmm9, xmm10 movdqa xmm4, xmm1 pslld xmm1, 20 psrld xmm4, 12 por xmm1, xmm4 movdqa xmm4, xmm9 pslld xmm9, 20 psrld xmm4, 12 por xmm9, xmm4 paddd xmm0, xmm5 paddd xmm8, xmm13 movaps xmmword ptr [rsp+0x40], xmm5 movaps xmmword ptr [rsp+0x50], xmm13 paddd xmm0, xmm1 paddd xmm8, xmm9 pxor xmm3, xmm0 pxor xmm11, xmm8 movdqa xmm13, xmm3 psrld xmm3, 8 pslld xmm13, 24 pxor xmm3, xmm13 movdqa xmm13, xmm11 psrld xmm11, 8 pslld xmm13, 24 pxor xmm11, xmm13 paddd xmm2, xmm3 paddd xmm10, xmm11 pxor xmm1, xmm2 pxor xmm9, xmm10 movdqa xmm4, xmm1 pslld xmm1, 25 psrld xmm4, 7 por xmm1, xmm4 movdqa xmm4, xmm9 pslld xmm9, 25 psrld xmm4, 7 por xmm9, xmm4 pshufd xmm0, xmm0, 0x93 pshufd xmm8, xmm8, 0x93 pshufd xmm3, xmm3, 0x4E pshufd xmm11, xmm11, 0x4E pshufd xmm2, xmm2, 0x39 pshufd xmm10, xmm10, 0x39 paddd xmm0, xmm6 paddd xmm8, xmm14 paddd xmm0, xmm1 paddd xmm8, xmm9 pxor xmm3, xmm0 pxor xmm11, xmm8 pshuflw xmm3, xmm3, 0xB1 pshufhw xmm3, xmm3, 0xB1 pshuflw xmm11, xmm11, 0xB1 pshufhw xmm11, xmm11, 0xB1 paddd xmm2, xmm3 paddd xmm10, xmm11 pxor xmm1, xmm2 pxor xmm9, xmm10 movdqa xmm4, xmm1 pslld xmm1, 20 psrld xmm4, 12 por xmm1, xmm4 movdqa xmm4, xmm9 pslld xmm9, 20 psrld xmm4, 12 por xmm9, xmm4 paddd xmm0, xmm7 paddd xmm8, xmm15 paddd xmm0, xmm1 paddd xmm8, xmm9 pxor xmm3, xmm0 pxor xmm11, xmm8 movdqa xmm13, xmm3 psrld xmm3, 8 pslld xmm13, 24 pxor xmm3, xmm13 movdqa xmm13, xmm11 psrld xmm11, 8 pslld xmm13, 24 pxor xmm11, xmm13 paddd xmm2, xmm3 paddd xmm10, xmm11 pxor xmm1, xmm2 pxor xmm9, xmm10 movdqa xmm4, xmm1 pslld xmm1, 25 psrld xmm4, 7 por xmm1, xmm4 movdqa xmm4, xmm9 pslld xmm9, 25 psrld xmm4, 7 por xmm9, xmm4 pshufd xmm0, xmm0, 0x39 pshufd xmm8, xmm8, 0x39 pshufd xmm3, xmm3, 0x4E pshufd xmm11, xmm11, 0x4E pshufd xmm2, xmm2, 0x93 pshufd xmm10, xmm10, 0x93 dec al je 9f movdqa xmm12, xmmword ptr [rsp+0x20] movdqa xmm5, xmmword ptr [rsp+0x40] pshufd xmm13, xmm12, 0x0F shufps xmm12, xmm5, 214 pshufd xmm4, xmm12, 0x39 movdqa xmm12, xmm6 shufps xmm12, xmm7, 250 pand xmm13, xmmword ptr [PBLENDW_0x33_MASK+rip] pand xmm12, xmmword ptr [PBLENDW_0xCC_MASK+rip] por xmm13, xmm12 movdqa xmmword ptr [rsp+0x20], xmm13 movdqa xmm12, xmm7 punpcklqdq xmm12, xmm5 movdqa xmm13, xmm6 pand xmm12, xmmword ptr [PBLENDW_0x3F_MASK+rip] pand xmm13, xmmword ptr [PBLENDW_0xC0_MASK+rip] por xmm12, xmm13 pshufd xmm12, xmm12, 0x78 punpckhdq xmm5, xmm7 punpckldq xmm6, xmm5 pshufd xmm7, xmm6, 0x1E movdqa xmmword ptr [rsp+0x40], xmm12 movdqa xmm5, xmmword ptr [rsp+0x30] movdqa xmm13, xmmword ptr [rsp+0x50] pshufd xmm6, xmm5, 0x0F shufps xmm5, xmm13, 214 pshufd xmm12, xmm5, 0x39 movdqa xmm5, xmm14 shufps xmm5, xmm15, 250 pand xmm6, xmmword ptr [PBLENDW_0x33_MASK+rip] pand xmm5, xmmword ptr [PBLENDW_0xCC_MASK+rip] por xmm6, xmm5 movdqa xmm5, xmm15 punpcklqdq xmm5, xmm13 movdqa xmmword ptr [rsp+0x30], xmm2 movdqa xmm2, xmm14 pand xmm5, xmmword ptr [PBLENDW_0x3F_MASK+rip] pand xmm2, xmmword ptr [PBLENDW_0xC0_MASK+rip] por xmm5, xmm2 movdqa xmm2, xmmword ptr [rsp+0x30] pshufd xmm5, xmm5, 0x78 punpckhdq xmm13, xmm15 punpckldq xmm14, xmm13 pshufd xmm15, xmm14, 0x1E movdqa xmm13, xmm6 movdqa xmm14, xmm5 movdqa xmm5, xmmword ptr [rsp+0x20] movdqa xmm6, xmmword ptr [rsp+0x40] jmp 9b 9: pxor xmm0, xmm2 pxor xmm1, xmm3 pxor xmm8, xmm10 pxor xmm9, xmm11 mov eax, r13d cmp rdx, r15 jne 2b movups xmmword ptr [rbx], xmm0 movups xmmword ptr [rbx+0x10], xmm1 movups xmmword ptr [rbx+0x20], xmm8 movups xmmword ptr [rbx+0x30], xmm9 mov eax, dword ptr [rsp+0x130] neg eax mov r10d, dword ptr [rsp+0x110+8*rax] mov r11d, dword ptr [rsp+0x120+8*rax] mov dword ptr [rsp+0x110], r10d mov dword ptr [rsp+0x120], r11d add rdi, 16 add rbx, 64 sub rsi, 2 3: test esi, 0x1 je 4b movups xmm0, xmmword ptr [rcx] movups xmm1, xmmword ptr [rcx+0x10] movd xmm13, dword ptr [rsp+0x110] movd xmm14, dword ptr [rsp+0x120] punpckldq xmm13, xmm14 mov r8, qword ptr [rdi] movzx eax, byte ptr [rbp+0x40] or eax, r13d xor edx, edx 2: mov r14d, eax or eax, r12d add rdx, 64 cmp rdx, r15 cmovne eax, r14d movaps xmm2, xmmword ptr [BLAKE3_IV+rip] shl rax, 32 or rax, 64 movq xmm12, rax movdqa xmm3, xmm13 punpcklqdq xmm3, xmm12 movups xmm4, xmmword ptr [r8+rdx-0x40] movups xmm5, xmmword ptr [r8+rdx-0x30] movaps xmm8, xmm4 shufps xmm4, xmm5, 136 shufps xmm8, xmm5, 221 movaps xmm5, xmm8 movups xmm6, xmmword ptr [r8+rdx-0x20] movups xmm7, xmmword ptr [r8+rdx-0x10] movaps xmm8, xmm6 shufps xmm6, xmm7, 136 pshufd xmm6, xmm6, 0x93 shufps xmm8, xmm7, 221 pshufd xmm7, xmm8, 0x93 mov al, 7 9: paddd xmm0, xmm4 paddd xmm0, xmm1 pxor xmm3, xmm0 pshuflw xmm3, xmm3, 0xB1 pshufhw xmm3, xmm3, 0xB1 paddd xmm2, xmm3 pxor xmm1, xmm2 movdqa xmm11, xmm1 pslld xmm1, 20 psrld xmm11, 12 por xmm1, xmm11 paddd xmm0, xmm5 paddd xmm0, xmm1 pxor xmm3, xmm0 movdqa xmm14, xmm3 psrld xmm3, 8 pslld xmm14, 24 pxor xmm3, xmm14 paddd xmm2, xmm3 pxor xmm1, xmm2 movdqa xmm11, xmm1 pslld xmm1, 25 psrld xmm11, 7 por xmm1, xmm11 pshufd xmm0, xmm0, 0x93 pshufd xmm3, xmm3, 0x4E pshufd xmm2, xmm2, 0x39 paddd xmm0, xmm6 paddd xmm0, xmm1 pxor xmm3, xmm0 pshuflw xmm3, xmm3, 0xB1 pshufhw xmm3, xmm3, 0xB1 paddd xmm2, xmm3 pxor xmm1, xmm2 movdqa xmm11, xmm1 pslld xmm1, 20 psrld xmm11, 12 por xmm1, xmm11 paddd xmm0, xmm7 paddd xmm0, xmm1 pxor xmm3, xmm0 movdqa xmm14, xmm3 psrld xmm3, 8 pslld xmm14, 24 pxor xmm3, xmm14 paddd xmm2, xmm3 pxor xmm1, xmm2 movdqa xmm11, xmm1 pslld xmm1, 25 psrld xmm11, 7 por xmm1, xmm11 pshufd xmm0, xmm0, 0x39 pshufd xmm3, xmm3, 0x4E pshufd xmm2, xmm2, 0x93 dec al jz 9f movdqa xmm8, xmm4 shufps xmm8, xmm5, 214 pshufd xmm9, xmm4, 0x0F pshufd xmm4, xmm8, 0x39 movdqa xmm8, xmm6 shufps xmm8, xmm7, 250 pand xmm9, xmmword ptr [PBLENDW_0x33_MASK+rip] pand xmm8, xmmword ptr [PBLENDW_0xCC_MASK+rip] por xmm9, xmm8 movdqa xmm8, xmm7 punpcklqdq xmm8, xmm5 movdqa xmm10, xmm6 pand xmm8, xmmword ptr [PBLENDW_0x3F_MASK+rip] pand xmm10, xmmword ptr [PBLENDW_0xC0_MASK+rip] por xmm8, xmm10 pshufd xmm8, xmm8, 0x78 punpckhdq xmm5, xmm7 punpckldq xmm6, xmm5 pshufd xmm7, xmm6, 0x1E movdqa xmm5, xmm9 movdqa xmm6, xmm8 jmp 9b 9: pxor xmm0, xmm2 pxor xmm1, xmm3 mov eax, r13d cmp rdx, r15 jne 2b movups xmmword ptr [rbx], xmm0 movups xmmword ptr [rbx+0x10], xmm1 jmp 4b .p2align 6 blake3_compress_in_place_sse2: _blake3_compress_in_place_sse2: _CET_ENDBR movups xmm0, xmmword ptr [rdi] movups xmm1, xmmword ptr [rdi+0x10] movaps xmm2, xmmword ptr [BLAKE3_IV+rip] shl r8, 32 add rdx, r8 movq xmm3, rcx movq xmm4, rdx punpcklqdq xmm3, xmm4 movups xmm4, xmmword ptr [rsi] movups xmm5, xmmword ptr [rsi+0x10] movaps xmm8, xmm4 shufps xmm4, xmm5, 136 shufps xmm8, xmm5, 221 movaps xmm5, xmm8 movups xmm6, xmmword ptr [rsi+0x20] movups xmm7, xmmword ptr [rsi+0x30] movaps xmm8, xmm6 shufps xmm6, xmm7, 136 pshufd xmm6, xmm6, 0x93 shufps xmm8, xmm7, 221 pshufd xmm7, xmm8, 0x93 mov al, 7 9: paddd xmm0, xmm4 paddd xmm0, xmm1 pxor xmm3, xmm0 pshuflw xmm3, xmm3, 0xB1 pshufhw xmm3, xmm3, 0xB1 paddd xmm2, xmm3 pxor xmm1, xmm2 movdqa xmm11, xmm1 pslld xmm1, 20 psrld xmm11, 12 por xmm1, xmm11 paddd xmm0, xmm5 paddd xmm0, xmm1 pxor xmm3, xmm0 movdqa xmm14, xmm3 psrld xmm3, 8 pslld xmm14, 24 pxor xmm3, xmm14 paddd xmm2, xmm3 pxor xmm1, xmm2 movdqa xmm11, xmm1 pslld xmm1, 25 psrld xmm11, 7 por xmm1, xmm11 pshufd xmm0, xmm0, 0x93 pshufd xmm3, xmm3, 0x4E pshufd xmm2, xmm2, 0x39 paddd xmm0, xmm6 paddd xmm0, xmm1 pxor xmm3, xmm0 pshuflw xmm3, xmm3, 0xB1 pshufhw xmm3, xmm3, 0xB1 paddd xmm2, xmm3 pxor xmm1, xmm2 movdqa xmm11, xmm1 pslld xmm1, 20 psrld xmm11, 12 por xmm1, xmm11 paddd xmm0, xmm7 paddd xmm0, xmm1 pxor xmm3, xmm0 movdqa xmm14, xmm3 psrld xmm3, 8 pslld xmm14, 24 pxor xmm3, xmm14 paddd xmm2, xmm3 pxor xmm1, xmm2 movdqa xmm11, xmm1 pslld xmm1, 25 psrld xmm11, 7 por xmm1, xmm11 pshufd xmm0, xmm0, 0x39 pshufd xmm3, xmm3, 0x4E pshufd xmm2, xmm2, 0x93 dec al jz 9f movdqa xmm8, xmm4 shufps xmm8, xmm5, 214 pshufd xmm9, xmm4, 0x0F pshufd xmm4, xmm8, 0x39 movdqa xmm8, xmm6 shufps xmm8, xmm7, 250 pand xmm9, xmmword ptr [PBLENDW_0x33_MASK+rip] pand xmm8, xmmword ptr [PBLENDW_0xCC_MASK+rip] por xmm9, xmm8 movdqa xmm8, xmm7 punpcklqdq xmm8, xmm5 movdqa xmm10, xmm6 pand xmm8, xmmword ptr [PBLENDW_0x3F_MASK+rip] pand xmm10, xmmword ptr [PBLENDW_0xC0_MASK+rip] por xmm8, xmm10 pshufd xmm8, xmm8, 0x78 punpckhdq xmm5, xmm7 punpckldq xmm6, xmm5 pshufd xmm7, xmm6, 0x1E movdqa xmm5, xmm9 movdqa xmm6, xmm8 jmp 9b 9: pxor xmm0, xmm2 pxor xmm1, xmm3 movups xmmword ptr [rdi], xmm0 movups xmmword ptr [rdi+0x10], xmm1 ret .p2align 6 blake3_compress_xof_sse2: _blake3_compress_xof_sse2: _CET_ENDBR movups xmm0, xmmword ptr [rdi] movups xmm1, xmmword ptr [rdi+0x10] movaps xmm2, xmmword ptr [BLAKE3_IV+rip] movzx eax, r8b movzx edx, dl shl rax, 32 add rdx, rax movq xmm3, rcx movq xmm4, rdx punpcklqdq xmm3, xmm4 movups xmm4, xmmword ptr [rsi] movups xmm5, xmmword ptr [rsi+0x10] movaps xmm8, xmm4 shufps xmm4, xmm5, 136 shufps xmm8, xmm5, 221 movaps xmm5, xmm8 movups xmm6, xmmword ptr [rsi+0x20] movups xmm7, xmmword ptr [rsi+0x30] movaps xmm8, xmm6 shufps xmm6, xmm7, 136 pshufd xmm6, xmm6, 0x93 shufps xmm8, xmm7, 221 pshufd xmm7, xmm8, 0x93 mov al, 7 9: paddd xmm0, xmm4 paddd xmm0, xmm1 pxor xmm3, xmm0 pshuflw xmm3, xmm3, 0xB1 pshufhw xmm3, xmm3, 0xB1 paddd xmm2, xmm3 pxor xmm1, xmm2 movdqa xmm11, xmm1 pslld xmm1, 20 psrld xmm11, 12 por xmm1, xmm11 paddd xmm0, xmm5 paddd xmm0, xmm1 pxor xmm3, xmm0 movdqa xmm14, xmm3 psrld xmm3, 8 pslld xmm14, 24 pxor xmm3, xmm14 paddd xmm2, xmm3 pxor xmm1, xmm2 movdqa xmm11, xmm1 pslld xmm1, 25 psrld xmm11, 7 por xmm1, xmm11 pshufd xmm0, xmm0, 0x93 pshufd xmm3, xmm3, 0x4E pshufd xmm2, xmm2, 0x39 paddd xmm0, xmm6 paddd xmm0, xmm1 pxor xmm3, xmm0 pshuflw xmm3, xmm3, 0xB1 pshufhw xmm3, xmm3, 0xB1 paddd xmm2, xmm3 pxor xmm1, xmm2 movdqa xmm11, xmm1 pslld xmm1, 20 psrld xmm11, 12 por xmm1, xmm11 paddd xmm0, xmm7 paddd xmm0, xmm1 pxor xmm3, xmm0 movdqa xmm14, xmm3 psrld xmm3, 8 pslld xmm14, 24 pxor xmm3, xmm14 paddd xmm2, xmm3 pxor xmm1, xmm2 movdqa xmm11, xmm1 pslld xmm1, 25 psrld xmm11, 7 por xmm1, xmm11 pshufd xmm0, xmm0, 0x39 pshufd xmm3, xmm3, 0x4E pshufd xmm2, xmm2, 0x93 dec al jz 9f movdqa xmm8, xmm4 shufps xmm8, xmm5, 214 pshufd xmm9, xmm4, 0x0F pshufd xmm4, xmm8, 0x39 movdqa xmm8, xmm6 shufps xmm8, xmm7, 250 pand xmm9, xmmword ptr [PBLENDW_0x33_MASK+rip] pand xmm8, xmmword ptr [PBLENDW_0xCC_MASK+rip] por xmm9, xmm8 movdqa xmm8, xmm7 punpcklqdq xmm8, xmm5 movdqa xmm10, xmm6 pand xmm8, xmmword ptr [PBLENDW_0x3F_MASK+rip] pand xmm10, xmmword ptr [PBLENDW_0xC0_MASK+rip] por xmm8, xmm10 pshufd xmm8, xmm8, 0x78 punpckhdq xmm5, xmm7 punpckldq xmm6, xmm5 pshufd xmm7, xmm6, 0x1E movdqa xmm5, xmm9 movdqa xmm6, xmm8 jmp 9b 9: movdqu xmm4, xmmword ptr [rdi] movdqu xmm5, xmmword ptr [rdi+0x10] pxor xmm0, xmm2 pxor xmm1, xmm3 pxor xmm2, xmm4 pxor xmm3, xmm5 movups xmmword ptr [r9], xmm0 movups xmmword ptr [r9+0x10], xmm1 movups xmmword ptr [r9+0x20], xmm2 movups xmmword ptr [r9+0x30], xmm3 ret #ifdef __APPLE__ .static_data #else .section .rodata #endif .p2align 6 BLAKE3_IV: .long 0x6A09E667, 0xBB67AE85 .long 0x3C6EF372, 0xA54FF53A ADD0: .long 0, 1, 2, 3 ADD1: .long 4, 4, 4, 4 BLAKE3_IV_0: .long 0x6A09E667, 0x6A09E667, 0x6A09E667, 0x6A09E667 BLAKE3_IV_1: .long 0xBB67AE85, 0xBB67AE85, 0xBB67AE85, 0xBB67AE85 BLAKE3_IV_2: .long 0x3C6EF372, 0x3C6EF372, 0x3C6EF372, 0x3C6EF372 BLAKE3_IV_3: .long 0xA54FF53A, 0xA54FF53A, 0xA54FF53A, 0xA54FF53A BLAKE3_BLOCK_LEN: .long 64, 64, 64, 64 CMP_MSB_MASK: .long 0x80000000, 0x80000000, 0x80000000, 0x80000000 PBLENDW_0x33_MASK: .long 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000 PBLENDW_0xCC_MASK: .long 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF PBLENDW_0x3F_MASK: .long 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000 PBLENDW_0xC0_MASK: .long 0x00000000, 0x00000000, 0x00000000, 0xFFFFFFFF librecast/libs/blake3/c/blake3_sse2_x86-64_windows_gnu.S000066400000000000000000002130421502456746400231610ustar00rootroot00000000000000.intel_syntax noprefix .global blake3_hash_many_sse2 .global _blake3_hash_many_sse2 .global blake3_compress_in_place_sse2 .global _blake3_compress_in_place_sse2 .global blake3_compress_xof_sse2 .global _blake3_compress_xof_sse2 .section .text .p2align 6 _blake3_hash_many_sse2: blake3_hash_many_sse2: push r15 push r14 push r13 push r12 push rsi push rdi push rbx push rbp mov rbp, rsp sub rsp, 528 and rsp, 0xFFFFFFFFFFFFFFC0 movdqa xmmword ptr [rsp+0x170], xmm6 movdqa xmmword ptr [rsp+0x180], xmm7 movdqa xmmword ptr [rsp+0x190], xmm8 movdqa xmmword ptr [rsp+0x1A0], xmm9 movdqa xmmword ptr [rsp+0x1B0], xmm10 movdqa xmmword ptr [rsp+0x1C0], xmm11 movdqa xmmword ptr [rsp+0x1D0], xmm12 movdqa xmmword ptr [rsp+0x1E0], xmm13 movdqa xmmword ptr [rsp+0x1F0], xmm14 movdqa xmmword ptr [rsp+0x200], xmm15 mov rdi, rcx mov rsi, rdx mov rdx, r8 mov rcx, r9 mov r8, qword ptr [rbp+0x68] movzx r9, byte ptr [rbp+0x70] neg r9d movd xmm0, r9d pshufd xmm0, xmm0, 0x00 movdqa xmmword ptr [rsp+0x130], xmm0 movdqa xmm1, xmm0 pand xmm1, xmmword ptr [ADD0+rip] pand xmm0, xmmword ptr [ADD1+rip] movdqa xmmword ptr [rsp+0x150], xmm0 movd xmm0, r8d pshufd xmm0, xmm0, 0x00 paddd xmm0, xmm1 movdqa xmmword ptr [rsp+0x110], xmm0 pxor xmm0, xmmword ptr [CMP_MSB_MASK+rip] pxor xmm1, xmmword ptr [CMP_MSB_MASK+rip] pcmpgtd xmm1, xmm0 shr r8, 32 movd xmm2, r8d pshufd xmm2, xmm2, 0x00 psubd xmm2, xmm1 movdqa xmmword ptr [rsp+0x120], xmm2 mov rbx, qword ptr [rbp+0x90] mov r15, rdx shl r15, 6 movzx r13d, byte ptr [rbp+0x78] movzx r12d, byte ptr [rbp+0x88] cmp rsi, 4 jc 3f 2: movdqu xmm3, xmmword ptr [rcx] pshufd xmm0, xmm3, 0x00 pshufd xmm1, xmm3, 0x55 pshufd xmm2, xmm3, 0xAA pshufd xmm3, xmm3, 0xFF movdqu xmm7, xmmword ptr [rcx+0x10] pshufd xmm4, xmm7, 0x00 pshufd xmm5, xmm7, 0x55 pshufd xmm6, xmm7, 0xAA pshufd xmm7, xmm7, 0xFF mov r8, qword ptr [rdi] mov r9, qword ptr [rdi+0x8] mov r10, qword ptr [rdi+0x10] mov r11, qword ptr [rdi+0x18] movzx eax, byte ptr [rbp+0x80] or eax, r13d xor edx, edx 9: mov r14d, eax or eax, r12d add rdx, 64 cmp rdx, r15 cmovne eax, r14d movdqu xmm8, xmmword ptr [r8+rdx-0x40] movdqu xmm9, xmmword ptr [r9+rdx-0x40] movdqu xmm10, xmmword ptr [r10+rdx-0x40] movdqu xmm11, xmmword ptr [r11+rdx-0x40] movdqa xmm12, xmm8 punpckldq xmm8, xmm9 punpckhdq xmm12, xmm9 movdqa xmm14, xmm10 punpckldq xmm10, xmm11 punpckhdq xmm14, xmm11 movdqa xmm9, xmm8 punpcklqdq xmm8, xmm10 punpckhqdq xmm9, xmm10 movdqa xmm13, xmm12 punpcklqdq xmm12, xmm14 punpckhqdq xmm13, xmm14 movdqa xmmword ptr [rsp], xmm8 movdqa xmmword ptr [rsp+0x10], xmm9 movdqa xmmword ptr [rsp+0x20], xmm12 movdqa xmmword ptr [rsp+0x30], xmm13 movdqu xmm8, xmmword ptr [r8+rdx-0x30] movdqu xmm9, xmmword ptr [r9+rdx-0x30] movdqu xmm10, xmmword ptr [r10+rdx-0x30] movdqu xmm11, xmmword ptr [r11+rdx-0x30] movdqa xmm12, xmm8 punpckldq xmm8, xmm9 punpckhdq xmm12, xmm9 movdqa xmm14, xmm10 punpckldq xmm10, xmm11 punpckhdq xmm14, xmm11 movdqa xmm9, xmm8 punpcklqdq xmm8, xmm10 punpckhqdq xmm9, xmm10 movdqa xmm13, xmm12 punpcklqdq xmm12, xmm14 punpckhqdq xmm13, xmm14 movdqa xmmword ptr [rsp+0x40], xmm8 movdqa xmmword ptr [rsp+0x50], xmm9 movdqa xmmword ptr [rsp+0x60], xmm12 movdqa xmmword ptr [rsp+0x70], xmm13 movdqu xmm8, xmmword ptr [r8+rdx-0x20] movdqu xmm9, xmmword ptr [r9+rdx-0x20] movdqu xmm10, xmmword ptr [r10+rdx-0x20] movdqu xmm11, xmmword ptr [r11+rdx-0x20] movdqa xmm12, xmm8 punpckldq xmm8, xmm9 punpckhdq xmm12, xmm9 movdqa xmm14, xmm10 punpckldq xmm10, xmm11 punpckhdq xmm14, xmm11 movdqa xmm9, xmm8 punpcklqdq xmm8, xmm10 punpckhqdq xmm9, xmm10 movdqa xmm13, xmm12 punpcklqdq xmm12, xmm14 punpckhqdq xmm13, xmm14 movdqa xmmword ptr [rsp+0x80], xmm8 movdqa xmmword ptr [rsp+0x90], xmm9 movdqa xmmword ptr [rsp+0xA0], xmm12 movdqa xmmword ptr [rsp+0xB0], xmm13 movdqu xmm8, xmmword ptr [r8+rdx-0x10] movdqu xmm9, xmmword ptr [r9+rdx-0x10] movdqu xmm10, xmmword ptr [r10+rdx-0x10] movdqu xmm11, xmmword ptr [r11+rdx-0x10] movdqa xmm12, xmm8 punpckldq xmm8, xmm9 punpckhdq xmm12, xmm9 movdqa xmm14, xmm10 punpckldq xmm10, xmm11 punpckhdq xmm14, xmm11 movdqa xmm9, xmm8 punpcklqdq xmm8, xmm10 punpckhqdq xmm9, xmm10 movdqa xmm13, xmm12 punpcklqdq xmm12, xmm14 punpckhqdq xmm13, xmm14 movdqa xmmword ptr [rsp+0xC0], xmm8 movdqa xmmword ptr [rsp+0xD0], xmm9 movdqa xmmword ptr [rsp+0xE0], xmm12 movdqa xmmword ptr [rsp+0xF0], xmm13 movdqa xmm9, xmmword ptr [BLAKE3_IV_1+rip] movdqa xmm10, xmmword ptr [BLAKE3_IV_2+rip] movdqa xmm11, xmmword ptr [BLAKE3_IV_3+rip] movdqa xmm12, xmmword ptr [rsp+0x110] movdqa xmm13, xmmword ptr [rsp+0x120] movdqa xmm14, xmmword ptr [BLAKE3_BLOCK_LEN+rip] movd xmm15, eax pshufd xmm15, xmm15, 0x00 prefetcht0 [r8+rdx+0x80] prefetcht0 [r9+rdx+0x80] prefetcht0 [r10+rdx+0x80] prefetcht0 [r11+rdx+0x80] paddd xmm0, xmmword ptr [rsp] paddd xmm1, xmmword ptr [rsp+0x20] paddd xmm2, xmmword ptr [rsp+0x40] paddd xmm3, xmmword ptr [rsp+0x60] paddd xmm0, xmm4 paddd xmm1, xmm5 paddd xmm2, xmm6 paddd xmm3, xmm7 pxor xmm12, xmm0 pxor xmm13, xmm1 pxor xmm14, xmm2 pxor xmm15, xmm3 pshuflw xmm12, xmm12, 0xB1 pshufhw xmm12, xmm12, 0xB1 pshuflw xmm13, xmm13, 0xB1 pshufhw xmm13, xmm13, 0xB1 pshuflw xmm14, xmm14, 0xB1 pshufhw xmm14, xmm14, 0xB1 pshuflw xmm15, xmm15, 0xB1 pshufhw xmm15, xmm15, 0xB1 movdqa xmm8, xmmword ptr [BLAKE3_IV_0+rip] paddd xmm8, xmm12 paddd xmm9, xmm13 paddd xmm10, xmm14 paddd xmm11, xmm15 pxor xmm4, xmm8 pxor xmm5, xmm9 pxor xmm6, xmm10 pxor xmm7, xmm11 movdqa xmmword ptr [rsp+0x100], xmm8 movdqa xmm8, xmm4 psrld xmm8, 12 pslld xmm4, 20 por xmm4, xmm8 movdqa xmm8, xmm5 psrld xmm8, 12 pslld xmm5, 20 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 12 pslld xmm6, 20 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 12 pslld xmm7, 20 por xmm7, xmm8 paddd xmm0, xmmword ptr [rsp+0x10] paddd xmm1, xmmword ptr [rsp+0x30] paddd xmm2, xmmword ptr [rsp+0x50] paddd xmm3, xmmword ptr [rsp+0x70] paddd xmm0, xmm4 paddd xmm1, xmm5 paddd xmm2, xmm6 paddd xmm3, xmm7 pxor xmm12, xmm0 pxor xmm13, xmm1 pxor xmm14, xmm2 pxor xmm15, xmm3 movdqa xmm8, xmm12 psrld xmm12, 8 pslld xmm8, 24 pxor xmm12, xmm8 movdqa xmm8, xmm13 psrld xmm13, 8 pslld xmm8, 24 pxor xmm13, xmm8 movdqa xmm8, xmm14 psrld xmm14, 8 pslld xmm8, 24 pxor xmm14, xmm8 movdqa xmm8, xmm15 psrld xmm15, 8 pslld xmm8, 24 pxor xmm15, xmm8 movdqa xmm8, xmmword ptr [rsp+0x100] paddd xmm8, xmm12 paddd xmm9, xmm13 paddd xmm10, xmm14 paddd xmm11, xmm15 pxor xmm4, xmm8 pxor xmm5, xmm9 pxor xmm6, xmm10 pxor xmm7, xmm11 movdqa xmmword ptr [rsp+0x100], xmm8 movdqa xmm8, xmm4 psrld xmm8, 7 pslld xmm4, 25 por xmm4, xmm8 movdqa xmm8, xmm5 psrld xmm8, 7 pslld xmm5, 25 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 7 pslld xmm6, 25 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 7 pslld xmm7, 25 por xmm7, xmm8 paddd xmm0, xmmword ptr [rsp+0x80] paddd xmm1, xmmword ptr [rsp+0xA0] paddd xmm2, xmmword ptr [rsp+0xC0] paddd xmm3, xmmword ptr [rsp+0xE0] paddd xmm0, xmm5 paddd xmm1, xmm6 paddd xmm2, xmm7 paddd xmm3, xmm4 pxor xmm15, xmm0 pxor xmm12, xmm1 pxor xmm13, xmm2 pxor xmm14, xmm3 pshuflw xmm15, xmm15, 0xB1 pshufhw xmm15, xmm15, 0xB1 pshuflw xmm12, xmm12, 0xB1 pshufhw xmm12, xmm12, 0xB1 pshuflw xmm13, xmm13, 0xB1 pshufhw xmm13, xmm13, 0xB1 pshuflw xmm14, xmm14, 0xB1 pshufhw xmm14, xmm14, 0xB1 paddd xmm10, xmm15 paddd xmm11, xmm12 movdqa xmm8, xmmword ptr [rsp+0x100] paddd xmm8, xmm13 paddd xmm9, xmm14 pxor xmm5, xmm10 pxor xmm6, xmm11 pxor xmm7, xmm8 pxor xmm4, xmm9 movdqa xmmword ptr [rsp+0x100], xmm8 movdqa xmm8, xmm5 psrld xmm8, 12 pslld xmm5, 20 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 12 pslld xmm6, 20 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 12 pslld xmm7, 20 por xmm7, xmm8 movdqa xmm8, xmm4 psrld xmm8, 12 pslld xmm4, 20 por xmm4, xmm8 paddd xmm0, xmmword ptr [rsp+0x90] paddd xmm1, xmmword ptr [rsp+0xB0] paddd xmm2, xmmword ptr [rsp+0xD0] paddd xmm3, xmmword ptr [rsp+0xF0] paddd xmm0, xmm5 paddd xmm1, xmm6 paddd xmm2, xmm7 paddd xmm3, xmm4 pxor xmm15, xmm0 pxor xmm12, xmm1 pxor xmm13, xmm2 pxor xmm14, xmm3 movdqa xmm8, xmm15 psrld xmm15, 8 pslld xmm8, 24 pxor xmm15, xmm8 movdqa xmm8, xmm12 psrld xmm12, 8 pslld xmm8, 24 pxor xmm12, xmm8 movdqa xmm8, xmm13 psrld xmm13, 8 pslld xmm8, 24 pxor xmm13, xmm8 movdqa xmm8, xmm14 psrld xmm14, 8 pslld xmm8, 24 pxor xmm14, xmm8 paddd xmm10, xmm15 paddd xmm11, xmm12 movdqa xmm8, xmmword ptr [rsp+0x100] paddd xmm8, xmm13 paddd xmm9, xmm14 pxor xmm5, xmm10 pxor xmm6, xmm11 pxor xmm7, xmm8 pxor xmm4, xmm9 movdqa xmmword ptr [rsp+0x100], xmm8 movdqa xmm8, xmm5 psrld xmm8, 7 pslld xmm5, 25 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 7 pslld xmm6, 25 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 7 pslld xmm7, 25 por xmm7, xmm8 movdqa xmm8, xmm4 psrld xmm8, 7 pslld xmm4, 25 por xmm4, xmm8 paddd xmm0, xmmword ptr [rsp+0x20] paddd xmm1, xmmword ptr [rsp+0x30] paddd xmm2, xmmword ptr [rsp+0x70] paddd xmm3, xmmword ptr [rsp+0x40] paddd xmm0, xmm4 paddd xmm1, xmm5 paddd xmm2, xmm6 paddd xmm3, xmm7 pxor xmm12, xmm0 pxor xmm13, xmm1 pxor xmm14, xmm2 pxor xmm15, xmm3 pshuflw xmm12, xmm12, 0xB1 pshufhw xmm12, xmm12, 0xB1 pshuflw xmm13, xmm13, 0xB1 pshufhw xmm13, xmm13, 0xB1 pshuflw xmm14, xmm14, 0xB1 pshufhw xmm14, xmm14, 0xB1 pshuflw xmm15, xmm15, 0xB1 pshufhw xmm15, xmm15, 0xB1 movdqa xmm8, xmmword ptr [rsp+0x100] paddd xmm8, xmm12 paddd xmm9, xmm13 paddd xmm10, xmm14 paddd xmm11, xmm15 pxor xmm4, xmm8 pxor xmm5, xmm9 pxor xmm6, xmm10 pxor xmm7, xmm11 movdqa xmmword ptr [rsp+0x100], xmm8 movdqa xmm8, xmm4 psrld xmm8, 12 pslld xmm4, 20 por xmm4, xmm8 movdqa xmm8, xmm5 psrld xmm8, 12 pslld xmm5, 20 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 12 pslld xmm6, 20 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 12 pslld xmm7, 20 por xmm7, xmm8 paddd xmm0, xmmword ptr [rsp+0x60] paddd xmm1, xmmword ptr [rsp+0xA0] paddd xmm2, xmmword ptr [rsp] paddd xmm3, xmmword ptr [rsp+0xD0] paddd xmm0, xmm4 paddd xmm1, xmm5 paddd xmm2, xmm6 paddd xmm3, xmm7 pxor xmm12, xmm0 pxor xmm13, xmm1 pxor xmm14, xmm2 pxor xmm15, xmm3 movdqa xmm8, xmm12 psrld xmm12, 8 pslld xmm8, 24 pxor xmm12, xmm8 movdqa xmm8, xmm13 psrld xmm13, 8 pslld xmm8, 24 pxor xmm13, xmm8 movdqa xmm8, xmm14 psrld xmm14, 8 pslld xmm8, 24 pxor xmm14, xmm8 movdqa xmm8, xmm15 psrld xmm15, 8 pslld xmm8, 24 pxor xmm15, xmm8 movdqa xmm8, xmmword ptr [rsp+0x100] paddd xmm8, xmm12 paddd xmm9, xmm13 paddd xmm10, xmm14 paddd xmm11, xmm15 pxor xmm4, xmm8 pxor xmm5, xmm9 pxor xmm6, xmm10 pxor xmm7, xmm11 movdqa xmmword ptr [rsp+0x100], xmm8 movdqa xmm8, xmm4 psrld xmm8, 7 pslld xmm4, 25 por xmm4, xmm8 movdqa xmm8, xmm5 psrld xmm8, 7 pslld xmm5, 25 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 7 pslld xmm6, 25 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 7 pslld xmm7, 25 por xmm7, xmm8 paddd xmm0, xmmword ptr [rsp+0x10] paddd xmm1, xmmword ptr [rsp+0xC0] paddd xmm2, xmmword ptr [rsp+0x90] paddd xmm3, xmmword ptr [rsp+0xF0] paddd xmm0, xmm5 paddd xmm1, xmm6 paddd xmm2, xmm7 paddd xmm3, xmm4 pxor xmm15, xmm0 pxor xmm12, xmm1 pxor xmm13, xmm2 pxor xmm14, xmm3 pshuflw xmm15, xmm15, 0xB1 pshufhw xmm15, xmm15, 0xB1 pshuflw xmm12, xmm12, 0xB1 pshufhw xmm12, xmm12, 0xB1 pshuflw xmm13, xmm13, 0xB1 pshufhw xmm13, xmm13, 0xB1 pshuflw xmm14, xmm14, 0xB1 pshufhw xmm14, xmm14, 0xB1 paddd xmm10, xmm15 paddd xmm11, xmm12 movdqa xmm8, xmmword ptr [rsp+0x100] paddd xmm8, xmm13 paddd xmm9, xmm14 pxor xmm5, xmm10 pxor xmm6, xmm11 pxor xmm7, xmm8 pxor xmm4, xmm9 movdqa xmmword ptr [rsp+0x100], xmm8 movdqa xmm8, xmm5 psrld xmm8, 12 pslld xmm5, 20 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 12 pslld xmm6, 20 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 12 pslld xmm7, 20 por xmm7, xmm8 movdqa xmm8, xmm4 psrld xmm8, 12 pslld xmm4, 20 por xmm4, xmm8 paddd xmm0, xmmword ptr [rsp+0xB0] paddd xmm1, xmmword ptr [rsp+0x50] paddd xmm2, xmmword ptr [rsp+0xE0] paddd xmm3, xmmword ptr [rsp+0x80] paddd xmm0, xmm5 paddd xmm1, xmm6 paddd xmm2, xmm7 paddd xmm3, xmm4 pxor xmm15, xmm0 pxor xmm12, xmm1 pxor xmm13, xmm2 pxor xmm14, xmm3 movdqa xmm8, xmm15 psrld xmm15, 8 pslld xmm8, 24 pxor xmm15, xmm8 movdqa xmm8, xmm12 psrld xmm12, 8 pslld xmm8, 24 pxor xmm12, xmm8 movdqa xmm8, xmm13 psrld xmm13, 8 pslld xmm8, 24 pxor xmm13, xmm8 movdqa xmm8, xmm14 psrld xmm14, 8 pslld xmm8, 24 pxor xmm14, xmm8 paddd xmm10, xmm15 paddd xmm11, xmm12 movdqa xmm8, xmmword ptr [rsp+0x100] paddd xmm8, xmm13 paddd xmm9, xmm14 pxor xmm5, xmm10 pxor xmm6, xmm11 pxor xmm7, xmm8 pxor xmm4, xmm9 movdqa xmmword ptr [rsp+0x100], xmm8 movdqa xmm8, xmm5 psrld xmm8, 7 pslld xmm5, 25 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 7 pslld xmm6, 25 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 7 pslld xmm7, 25 por xmm7, xmm8 movdqa xmm8, xmm4 psrld xmm8, 7 pslld xmm4, 25 por xmm4, xmm8 paddd xmm0, xmmword ptr [rsp+0x30] paddd xmm1, xmmword ptr [rsp+0xA0] paddd xmm2, xmmword ptr [rsp+0xD0] paddd xmm3, xmmword ptr [rsp+0x70] paddd xmm0, xmm4 paddd xmm1, xmm5 paddd xmm2, xmm6 paddd xmm3, xmm7 pxor xmm12, xmm0 pxor xmm13, xmm1 pxor xmm14, xmm2 pxor xmm15, xmm3 pshuflw xmm12, xmm12, 0xB1 pshufhw xmm12, xmm12, 0xB1 pshuflw xmm13, xmm13, 0xB1 pshufhw xmm13, xmm13, 0xB1 pshuflw xmm14, xmm14, 0xB1 pshufhw xmm14, xmm14, 0xB1 pshuflw xmm15, xmm15, 0xB1 pshufhw xmm15, xmm15, 0xB1 movdqa xmm8, xmmword ptr [rsp+0x100] paddd xmm8, xmm12 paddd xmm9, xmm13 paddd xmm10, xmm14 paddd xmm11, xmm15 pxor xmm4, xmm8 pxor xmm5, xmm9 pxor xmm6, xmm10 pxor xmm7, xmm11 movdqa xmmword ptr [rsp+0x100], xmm8 movdqa xmm8, xmm4 psrld xmm8, 12 pslld xmm4, 20 por xmm4, xmm8 movdqa xmm8, xmm5 psrld xmm8, 12 pslld xmm5, 20 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 12 pslld xmm6, 20 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 12 pslld xmm7, 20 por xmm7, xmm8 paddd xmm0, xmmword ptr [rsp+0x40] paddd xmm1, xmmword ptr [rsp+0xC0] paddd xmm2, xmmword ptr [rsp+0x20] paddd xmm3, xmmword ptr [rsp+0xE0] paddd xmm0, xmm4 paddd xmm1, xmm5 paddd xmm2, xmm6 paddd xmm3, xmm7 pxor xmm12, xmm0 pxor xmm13, xmm1 pxor xmm14, xmm2 pxor xmm15, xmm3 movdqa xmm8, xmm12 psrld xmm12, 8 pslld xmm8, 24 pxor xmm12, xmm8 movdqa xmm8, xmm13 psrld xmm13, 8 pslld xmm8, 24 pxor xmm13, xmm8 movdqa xmm8, xmm14 psrld xmm14, 8 pslld xmm8, 24 pxor xmm14, xmm8 movdqa xmm8, xmm15 psrld xmm15, 8 pslld xmm8, 24 pxor xmm15, xmm8 movdqa xmm8, xmmword ptr [rsp+0x100] paddd xmm8, xmm12 paddd xmm9, xmm13 paddd xmm10, xmm14 paddd xmm11, xmm15 pxor xmm4, xmm8 pxor xmm5, xmm9 pxor xmm6, xmm10 pxor xmm7, xmm11 movdqa xmmword ptr [rsp+0x100], xmm8 movdqa xmm8, xmm4 psrld xmm8, 7 pslld xmm4, 25 por xmm4, xmm8 movdqa xmm8, xmm5 psrld xmm8, 7 pslld xmm5, 25 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 7 pslld xmm6, 25 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 7 pslld xmm7, 25 por xmm7, xmm8 paddd xmm0, xmmword ptr [rsp+0x60] paddd xmm1, xmmword ptr [rsp+0x90] paddd xmm2, xmmword ptr [rsp+0xB0] paddd xmm3, xmmword ptr [rsp+0x80] paddd xmm0, xmm5 paddd xmm1, xmm6 paddd xmm2, xmm7 paddd xmm3, xmm4 pxor xmm15, xmm0 pxor xmm12, xmm1 pxor xmm13, xmm2 pxor xmm14, xmm3 pshuflw xmm15, xmm15, 0xB1 pshufhw xmm15, xmm15, 0xB1 pshuflw xmm12, xmm12, 0xB1 pshufhw xmm12, xmm12, 0xB1 pshuflw xmm13, xmm13, 0xB1 pshufhw xmm13, xmm13, 0xB1 pshuflw xmm14, xmm14, 0xB1 pshufhw xmm14, xmm14, 0xB1 paddd xmm10, xmm15 paddd xmm11, xmm12 movdqa xmm8, xmmword ptr [rsp+0x100] paddd xmm8, xmm13 paddd xmm9, xmm14 pxor xmm5, xmm10 pxor xmm6, xmm11 pxor xmm7, xmm8 pxor xmm4, xmm9 movdqa xmmword ptr [rsp+0x100], xmm8 movdqa xmm8, xmm5 psrld xmm8, 12 pslld xmm5, 20 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 12 pslld xmm6, 20 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 12 pslld xmm7, 20 por xmm7, xmm8 movdqa xmm8, xmm4 psrld xmm8, 12 pslld xmm4, 20 por xmm4, xmm8 paddd xmm0, xmmword ptr [rsp+0x50] paddd xmm1, xmmword ptr [rsp] paddd xmm2, xmmword ptr [rsp+0xF0] paddd xmm3, xmmword ptr [rsp+0x10] paddd xmm0, xmm5 paddd xmm1, xmm6 paddd xmm2, xmm7 paddd xmm3, xmm4 pxor xmm15, xmm0 pxor xmm12, xmm1 pxor xmm13, xmm2 pxor xmm14, xmm3 movdqa xmm8, xmm15 psrld xmm15, 8 pslld xmm8, 24 pxor xmm15, xmm8 movdqa xmm8, xmm12 psrld xmm12, 8 pslld xmm8, 24 pxor xmm12, xmm8 movdqa xmm8, xmm13 psrld xmm13, 8 pslld xmm8, 24 pxor xmm13, xmm8 movdqa xmm8, xmm14 psrld xmm14, 8 pslld xmm8, 24 pxor xmm14, xmm8 paddd xmm10, xmm15 paddd xmm11, xmm12 movdqa xmm8, xmmword ptr [rsp+0x100] paddd xmm8, xmm13 paddd xmm9, xmm14 pxor xmm5, xmm10 pxor xmm6, xmm11 pxor xmm7, xmm8 pxor xmm4, xmm9 movdqa xmmword ptr [rsp+0x100], xmm8 movdqa xmm8, xmm5 psrld xmm8, 7 pslld xmm5, 25 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 7 pslld xmm6, 25 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 7 pslld xmm7, 25 por xmm7, xmm8 movdqa xmm8, xmm4 psrld xmm8, 7 pslld xmm4, 25 por xmm4, xmm8 paddd xmm0, xmmword ptr [rsp+0xA0] paddd xmm1, xmmword ptr [rsp+0xC0] paddd xmm2, xmmword ptr [rsp+0xE0] paddd xmm3, xmmword ptr [rsp+0xD0] paddd xmm0, xmm4 paddd xmm1, xmm5 paddd xmm2, xmm6 paddd xmm3, xmm7 pxor xmm12, xmm0 pxor xmm13, xmm1 pxor xmm14, xmm2 pxor xmm15, xmm3 pshuflw xmm12, xmm12, 0xB1 pshufhw xmm12, xmm12, 0xB1 pshuflw xmm13, xmm13, 0xB1 pshufhw xmm13, xmm13, 0xB1 pshuflw xmm14, xmm14, 0xB1 pshufhw xmm14, xmm14, 0xB1 pshuflw xmm15, xmm15, 0xB1 pshufhw xmm15, xmm15, 0xB1 movdqa xmm8, xmmword ptr [rsp+0x100] paddd xmm8, xmm12 paddd xmm9, xmm13 paddd xmm10, xmm14 paddd xmm11, xmm15 pxor xmm4, xmm8 pxor xmm5, xmm9 pxor xmm6, xmm10 pxor xmm7, xmm11 movdqa xmmword ptr [rsp+0x100], xmm8 movdqa xmm8, xmm4 psrld xmm8, 12 pslld xmm4, 20 por xmm4, xmm8 movdqa xmm8, xmm5 psrld xmm8, 12 pslld xmm5, 20 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 12 pslld xmm6, 20 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 12 pslld xmm7, 20 por xmm7, xmm8 paddd xmm0, xmmword ptr [rsp+0x70] paddd xmm1, xmmword ptr [rsp+0x90] paddd xmm2, xmmword ptr [rsp+0x30] paddd xmm3, xmmword ptr [rsp+0xF0] paddd xmm0, xmm4 paddd xmm1, xmm5 paddd xmm2, xmm6 paddd xmm3, xmm7 pxor xmm12, xmm0 pxor xmm13, xmm1 pxor xmm14, xmm2 pxor xmm15, xmm3 movdqa xmm8, xmm12 psrld xmm12, 8 pslld xmm8, 24 pxor xmm12, xmm8 movdqa xmm8, xmm13 psrld xmm13, 8 pslld xmm8, 24 pxor xmm13, xmm8 movdqa xmm8, xmm14 psrld xmm14, 8 pslld xmm8, 24 pxor xmm14, xmm8 movdqa xmm8, xmm15 psrld xmm15, 8 pslld xmm8, 24 pxor xmm15, xmm8 movdqa xmm8, xmmword ptr [rsp+0x100] paddd xmm8, xmm12 paddd xmm9, xmm13 paddd xmm10, xmm14 paddd xmm11, xmm15 pxor xmm4, xmm8 pxor xmm5, xmm9 pxor xmm6, xmm10 pxor xmm7, xmm11 movdqa xmmword ptr [rsp+0x100], xmm8 movdqa xmm8, xmm4 psrld xmm8, 7 pslld xmm4, 25 por xmm4, xmm8 movdqa xmm8, xmm5 psrld xmm8, 7 pslld xmm5, 25 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 7 pslld xmm6, 25 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 7 pslld xmm7, 25 por xmm7, xmm8 paddd xmm0, xmmword ptr [rsp+0x40] paddd xmm1, xmmword ptr [rsp+0xB0] paddd xmm2, xmmword ptr [rsp+0x50] paddd xmm3, xmmword ptr [rsp+0x10] paddd xmm0, xmm5 paddd xmm1, xmm6 paddd xmm2, xmm7 paddd xmm3, xmm4 pxor xmm15, xmm0 pxor xmm12, xmm1 pxor xmm13, xmm2 pxor xmm14, xmm3 pshuflw xmm15, xmm15, 0xB1 pshufhw xmm15, xmm15, 0xB1 pshuflw xmm12, xmm12, 0xB1 pshufhw xmm12, xmm12, 0xB1 pshuflw xmm13, xmm13, 0xB1 pshufhw xmm13, xmm13, 0xB1 pshuflw xmm14, xmm14, 0xB1 pshufhw xmm14, xmm14, 0xB1 paddd xmm10, xmm15 paddd xmm11, xmm12 movdqa xmm8, xmmword ptr [rsp+0x100] paddd xmm8, xmm13 paddd xmm9, xmm14 pxor xmm5, xmm10 pxor xmm6, xmm11 pxor xmm7, xmm8 pxor xmm4, xmm9 movdqa xmmword ptr [rsp+0x100], xmm8 movdqa xmm8, xmm5 psrld xmm8, 12 pslld xmm5, 20 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 12 pslld xmm6, 20 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 12 pslld xmm7, 20 por xmm7, xmm8 movdqa xmm8, xmm4 psrld xmm8, 12 pslld xmm4, 20 por xmm4, xmm8 paddd xmm0, xmmword ptr [rsp] paddd xmm1, xmmword ptr [rsp+0x20] paddd xmm2, xmmword ptr [rsp+0x80] paddd xmm3, xmmword ptr [rsp+0x60] paddd xmm0, xmm5 paddd xmm1, xmm6 paddd xmm2, xmm7 paddd xmm3, xmm4 pxor xmm15, xmm0 pxor xmm12, xmm1 pxor xmm13, xmm2 pxor xmm14, xmm3 movdqa xmm8, xmm15 psrld xmm15, 8 pslld xmm8, 24 pxor xmm15, xmm8 movdqa xmm8, xmm12 psrld xmm12, 8 pslld xmm8, 24 pxor xmm12, xmm8 movdqa xmm8, xmm13 psrld xmm13, 8 pslld xmm8, 24 pxor xmm13, xmm8 movdqa xmm8, xmm14 psrld xmm14, 8 pslld xmm8, 24 pxor xmm14, xmm8 paddd xmm10, xmm15 paddd xmm11, xmm12 movdqa xmm8, xmmword ptr [rsp+0x100] paddd xmm8, xmm13 paddd xmm9, xmm14 pxor xmm5, xmm10 pxor xmm6, xmm11 pxor xmm7, xmm8 pxor xmm4, xmm9 movdqa xmmword ptr [rsp+0x100], xmm8 movdqa xmm8, xmm5 psrld xmm8, 7 pslld xmm5, 25 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 7 pslld xmm6, 25 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 7 pslld xmm7, 25 por xmm7, xmm8 movdqa xmm8, xmm4 psrld xmm8, 7 pslld xmm4, 25 por xmm4, xmm8 paddd xmm0, xmmword ptr [rsp+0xC0] paddd xmm1, xmmword ptr [rsp+0x90] paddd xmm2, xmmword ptr [rsp+0xF0] paddd xmm3, xmmword ptr [rsp+0xE0] paddd xmm0, xmm4 paddd xmm1, xmm5 paddd xmm2, xmm6 paddd xmm3, xmm7 pxor xmm12, xmm0 pxor xmm13, xmm1 pxor xmm14, xmm2 pxor xmm15, xmm3 pshuflw xmm12, xmm12, 0xB1 pshufhw xmm12, xmm12, 0xB1 pshuflw xmm13, xmm13, 0xB1 pshufhw xmm13, xmm13, 0xB1 pshuflw xmm14, xmm14, 0xB1 pshufhw xmm14, xmm14, 0xB1 pshuflw xmm15, xmm15, 0xB1 pshufhw xmm15, xmm15, 0xB1 movdqa xmm8, xmmword ptr [rsp+0x100] paddd xmm8, xmm12 paddd xmm9, xmm13 paddd xmm10, xmm14 paddd xmm11, xmm15 pxor xmm4, xmm8 pxor xmm5, xmm9 pxor xmm6, xmm10 pxor xmm7, xmm11 movdqa xmmword ptr [rsp+0x100], xmm8 movdqa xmm8, xmm4 psrld xmm8, 12 pslld xmm4, 20 por xmm4, xmm8 movdqa xmm8, xmm5 psrld xmm8, 12 pslld xmm5, 20 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 12 pslld xmm6, 20 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 12 pslld xmm7, 20 por xmm7, xmm8 paddd xmm0, xmmword ptr [rsp+0xD0] paddd xmm1, xmmword ptr [rsp+0xB0] paddd xmm2, xmmword ptr [rsp+0xA0] paddd xmm3, xmmword ptr [rsp+0x80] paddd xmm0, xmm4 paddd xmm1, xmm5 paddd xmm2, xmm6 paddd xmm3, xmm7 pxor xmm12, xmm0 pxor xmm13, xmm1 pxor xmm14, xmm2 pxor xmm15, xmm3 movdqa xmm8, xmm12 psrld xmm12, 8 pslld xmm8, 24 pxor xmm12, xmm8 movdqa xmm8, xmm13 psrld xmm13, 8 pslld xmm8, 24 pxor xmm13, xmm8 movdqa xmm8, xmm14 psrld xmm14, 8 pslld xmm8, 24 pxor xmm14, xmm8 movdqa xmm8, xmm15 psrld xmm15, 8 pslld xmm8, 24 pxor xmm15, xmm8 movdqa xmm8, xmmword ptr [rsp+0x100] paddd xmm8, xmm12 paddd xmm9, xmm13 paddd xmm10, xmm14 paddd xmm11, xmm15 pxor xmm4, xmm8 pxor xmm5, xmm9 pxor xmm6, xmm10 pxor xmm7, xmm11 movdqa xmmword ptr [rsp+0x100], xmm8 movdqa xmm8, xmm4 psrld xmm8, 7 pslld xmm4, 25 por xmm4, xmm8 movdqa xmm8, xmm5 psrld xmm8, 7 pslld xmm5, 25 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 7 pslld xmm6, 25 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 7 pslld xmm7, 25 por xmm7, xmm8 paddd xmm0, xmmword ptr [rsp+0x70] paddd xmm1, xmmword ptr [rsp+0x50] paddd xmm2, xmmword ptr [rsp] paddd xmm3, xmmword ptr [rsp+0x60] paddd xmm0, xmm5 paddd xmm1, xmm6 paddd xmm2, xmm7 paddd xmm3, xmm4 pxor xmm15, xmm0 pxor xmm12, xmm1 pxor xmm13, xmm2 pxor xmm14, xmm3 pshuflw xmm15, xmm15, 0xB1 pshufhw xmm15, xmm15, 0xB1 pshuflw xmm12, xmm12, 0xB1 pshufhw xmm12, xmm12, 0xB1 pshuflw xmm13, xmm13, 0xB1 pshufhw xmm13, xmm13, 0xB1 pshuflw xmm14, xmm14, 0xB1 pshufhw xmm14, xmm14, 0xB1 paddd xmm10, xmm15 paddd xmm11, xmm12 movdqa xmm8, xmmword ptr [rsp+0x100] paddd xmm8, xmm13 paddd xmm9, xmm14 pxor xmm5, xmm10 pxor xmm6, xmm11 pxor xmm7, xmm8 pxor xmm4, xmm9 movdqa xmmword ptr [rsp+0x100], xmm8 movdqa xmm8, xmm5 psrld xmm8, 12 pslld xmm5, 20 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 12 pslld xmm6, 20 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 12 pslld xmm7, 20 por xmm7, xmm8 movdqa xmm8, xmm4 psrld xmm8, 12 pslld xmm4, 20 por xmm4, xmm8 paddd xmm0, xmmword ptr [rsp+0x20] paddd xmm1, xmmword ptr [rsp+0x30] paddd xmm2, xmmword ptr [rsp+0x10] paddd xmm3, xmmword ptr [rsp+0x40] paddd xmm0, xmm5 paddd xmm1, xmm6 paddd xmm2, xmm7 paddd xmm3, xmm4 pxor xmm15, xmm0 pxor xmm12, xmm1 pxor xmm13, xmm2 pxor xmm14, xmm3 movdqa xmm8, xmm15 psrld xmm15, 8 pslld xmm8, 24 pxor xmm15, xmm8 movdqa xmm8, xmm12 psrld xmm12, 8 pslld xmm8, 24 pxor xmm12, xmm8 movdqa xmm8, xmm13 psrld xmm13, 8 pslld xmm8, 24 pxor xmm13, xmm8 movdqa xmm8, xmm14 psrld xmm14, 8 pslld xmm8, 24 pxor xmm14, xmm8 paddd xmm10, xmm15 paddd xmm11, xmm12 movdqa xmm8, xmmword ptr [rsp+0x100] paddd xmm8, xmm13 paddd xmm9, xmm14 pxor xmm5, xmm10 pxor xmm6, xmm11 pxor xmm7, xmm8 pxor xmm4, xmm9 movdqa xmmword ptr [rsp+0x100], xmm8 movdqa xmm8, xmm5 psrld xmm8, 7 pslld xmm5, 25 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 7 pslld xmm6, 25 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 7 pslld xmm7, 25 por xmm7, xmm8 movdqa xmm8, xmm4 psrld xmm8, 7 pslld xmm4, 25 por xmm4, xmm8 paddd xmm0, xmmword ptr [rsp+0x90] paddd xmm1, xmmword ptr [rsp+0xB0] paddd xmm2, xmmword ptr [rsp+0x80] paddd xmm3, xmmword ptr [rsp+0xF0] paddd xmm0, xmm4 paddd xmm1, xmm5 paddd xmm2, xmm6 paddd xmm3, xmm7 pxor xmm12, xmm0 pxor xmm13, xmm1 pxor xmm14, xmm2 pxor xmm15, xmm3 pshuflw xmm12, xmm12, 0xB1 pshufhw xmm12, xmm12, 0xB1 pshuflw xmm13, xmm13, 0xB1 pshufhw xmm13, xmm13, 0xB1 pshuflw xmm14, xmm14, 0xB1 pshufhw xmm14, xmm14, 0xB1 pshuflw xmm15, xmm15, 0xB1 pshufhw xmm15, xmm15, 0xB1 movdqa xmm8, xmmword ptr [rsp+0x100] paddd xmm8, xmm12 paddd xmm9, xmm13 paddd xmm10, xmm14 paddd xmm11, xmm15 pxor xmm4, xmm8 pxor xmm5, xmm9 pxor xmm6, xmm10 pxor xmm7, xmm11 movdqa xmmword ptr [rsp+0x100], xmm8 movdqa xmm8, xmm4 psrld xmm8, 12 pslld xmm4, 20 por xmm4, xmm8 movdqa xmm8, xmm5 psrld xmm8, 12 pslld xmm5, 20 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 12 pslld xmm6, 20 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 12 pslld xmm7, 20 por xmm7, xmm8 paddd xmm0, xmmword ptr [rsp+0xE0] paddd xmm1, xmmword ptr [rsp+0x50] paddd xmm2, xmmword ptr [rsp+0xC0] paddd xmm3, xmmword ptr [rsp+0x10] paddd xmm0, xmm4 paddd xmm1, xmm5 paddd xmm2, xmm6 paddd xmm3, xmm7 pxor xmm12, xmm0 pxor xmm13, xmm1 pxor xmm14, xmm2 pxor xmm15, xmm3 movdqa xmm8, xmm12 psrld xmm12, 8 pslld xmm8, 24 pxor xmm12, xmm8 movdqa xmm8, xmm13 psrld xmm13, 8 pslld xmm8, 24 pxor xmm13, xmm8 movdqa xmm8, xmm14 psrld xmm14, 8 pslld xmm8, 24 pxor xmm14, xmm8 movdqa xmm8, xmm15 psrld xmm15, 8 pslld xmm8, 24 pxor xmm15, xmm8 movdqa xmm8, xmmword ptr [rsp+0x100] paddd xmm8, xmm12 paddd xmm9, xmm13 paddd xmm10, xmm14 paddd xmm11, xmm15 pxor xmm4, xmm8 pxor xmm5, xmm9 pxor xmm6, xmm10 pxor xmm7, xmm11 movdqa xmmword ptr [rsp+0x100], xmm8 movdqa xmm8, xmm4 psrld xmm8, 7 pslld xmm4, 25 por xmm4, xmm8 movdqa xmm8, xmm5 psrld xmm8, 7 pslld xmm5, 25 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 7 pslld xmm6, 25 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 7 pslld xmm7, 25 por xmm7, xmm8 paddd xmm0, xmmword ptr [rsp+0xD0] paddd xmm1, xmmword ptr [rsp] paddd xmm2, xmmword ptr [rsp+0x20] paddd xmm3, xmmword ptr [rsp+0x40] paddd xmm0, xmm5 paddd xmm1, xmm6 paddd xmm2, xmm7 paddd xmm3, xmm4 pxor xmm15, xmm0 pxor xmm12, xmm1 pxor xmm13, xmm2 pxor xmm14, xmm3 pshuflw xmm15, xmm15, 0xB1 pshufhw xmm15, xmm15, 0xB1 pshuflw xmm12, xmm12, 0xB1 pshufhw xmm12, xmm12, 0xB1 pshuflw xmm13, xmm13, 0xB1 pshufhw xmm13, xmm13, 0xB1 pshuflw xmm14, xmm14, 0xB1 pshufhw xmm14, xmm14, 0xB1 paddd xmm10, xmm15 paddd xmm11, xmm12 movdqa xmm8, xmmword ptr [rsp+0x100] paddd xmm8, xmm13 paddd xmm9, xmm14 pxor xmm5, xmm10 pxor xmm6, xmm11 pxor xmm7, xmm8 pxor xmm4, xmm9 movdqa xmmword ptr [rsp+0x100], xmm8 movdqa xmm8, xmm5 psrld xmm8, 12 pslld xmm5, 20 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 12 pslld xmm6, 20 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 12 pslld xmm7, 20 por xmm7, xmm8 movdqa xmm8, xmm4 psrld xmm8, 12 pslld xmm4, 20 por xmm4, xmm8 paddd xmm0, xmmword ptr [rsp+0x30] paddd xmm1, xmmword ptr [rsp+0xA0] paddd xmm2, xmmword ptr [rsp+0x60] paddd xmm3, xmmword ptr [rsp+0x70] paddd xmm0, xmm5 paddd xmm1, xmm6 paddd xmm2, xmm7 paddd xmm3, xmm4 pxor xmm15, xmm0 pxor xmm12, xmm1 pxor xmm13, xmm2 pxor xmm14, xmm3 movdqa xmm8, xmm15 psrld xmm15, 8 pslld xmm8, 24 pxor xmm15, xmm8 movdqa xmm8, xmm12 psrld xmm12, 8 pslld xmm8, 24 pxor xmm12, xmm8 movdqa xmm8, xmm13 psrld xmm13, 8 pslld xmm8, 24 pxor xmm13, xmm8 movdqa xmm8, xmm14 psrld xmm14, 8 pslld xmm8, 24 pxor xmm14, xmm8 paddd xmm10, xmm15 paddd xmm11, xmm12 movdqa xmm8, xmmword ptr [rsp+0x100] paddd xmm8, xmm13 paddd xmm9, xmm14 pxor xmm5, xmm10 pxor xmm6, xmm11 pxor xmm7, xmm8 pxor xmm4, xmm9 movdqa xmmword ptr [rsp+0x100], xmm8 movdqa xmm8, xmm5 psrld xmm8, 7 pslld xmm5, 25 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 7 pslld xmm6, 25 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 7 pslld xmm7, 25 por xmm7, xmm8 movdqa xmm8, xmm4 psrld xmm8, 7 pslld xmm4, 25 por xmm4, xmm8 paddd xmm0, xmmword ptr [rsp+0xB0] paddd xmm1, xmmword ptr [rsp+0x50] paddd xmm2, xmmword ptr [rsp+0x10] paddd xmm3, xmmword ptr [rsp+0x80] paddd xmm0, xmm4 paddd xmm1, xmm5 paddd xmm2, xmm6 paddd xmm3, xmm7 pxor xmm12, xmm0 pxor xmm13, xmm1 pxor xmm14, xmm2 pxor xmm15, xmm3 pshuflw xmm12, xmm12, 0xB1 pshufhw xmm12, xmm12, 0xB1 pshuflw xmm13, xmm13, 0xB1 pshufhw xmm13, xmm13, 0xB1 pshuflw xmm14, xmm14, 0xB1 pshufhw xmm14, xmm14, 0xB1 pshuflw xmm15, xmm15, 0xB1 pshufhw xmm15, xmm15, 0xB1 movdqa xmm8, xmmword ptr [rsp+0x100] paddd xmm8, xmm12 paddd xmm9, xmm13 paddd xmm10, xmm14 paddd xmm11, xmm15 pxor xmm4, xmm8 pxor xmm5, xmm9 pxor xmm6, xmm10 pxor xmm7, xmm11 movdqa xmmword ptr [rsp+0x100], xmm8 movdqa xmm8, xmm4 psrld xmm8, 12 pslld xmm4, 20 por xmm4, xmm8 movdqa xmm8, xmm5 psrld xmm8, 12 pslld xmm5, 20 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 12 pslld xmm6, 20 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 12 pslld xmm7, 20 por xmm7, xmm8 paddd xmm0, xmmword ptr [rsp+0xF0] paddd xmm1, xmmword ptr [rsp] paddd xmm2, xmmword ptr [rsp+0x90] paddd xmm3, xmmword ptr [rsp+0x60] paddd xmm0, xmm4 paddd xmm1, xmm5 paddd xmm2, xmm6 paddd xmm3, xmm7 pxor xmm12, xmm0 pxor xmm13, xmm1 pxor xmm14, xmm2 pxor xmm15, xmm3 movdqa xmm8, xmm12 psrld xmm12, 8 pslld xmm8, 24 pxor xmm12, xmm8 movdqa xmm8, xmm13 psrld xmm13, 8 pslld xmm8, 24 pxor xmm13, xmm8 movdqa xmm8, xmm14 psrld xmm14, 8 pslld xmm8, 24 pxor xmm14, xmm8 movdqa xmm8, xmm15 psrld xmm15, 8 pslld xmm8, 24 pxor xmm15, xmm8 movdqa xmm8, xmmword ptr [rsp+0x100] paddd xmm8, xmm12 paddd xmm9, xmm13 paddd xmm10, xmm14 paddd xmm11, xmm15 pxor xmm4, xmm8 pxor xmm5, xmm9 pxor xmm6, xmm10 pxor xmm7, xmm11 movdqa xmmword ptr [rsp+0x100], xmm8 movdqa xmm8, xmm4 psrld xmm8, 7 pslld xmm4, 25 por xmm4, xmm8 movdqa xmm8, xmm5 psrld xmm8, 7 pslld xmm5, 25 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 7 pslld xmm6, 25 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 7 pslld xmm7, 25 por xmm7, xmm8 paddd xmm0, xmmword ptr [rsp+0xE0] paddd xmm1, xmmword ptr [rsp+0x20] paddd xmm2, xmmword ptr [rsp+0x30] paddd xmm3, xmmword ptr [rsp+0x70] paddd xmm0, xmm5 paddd xmm1, xmm6 paddd xmm2, xmm7 paddd xmm3, xmm4 pxor xmm15, xmm0 pxor xmm12, xmm1 pxor xmm13, xmm2 pxor xmm14, xmm3 pshuflw xmm15, xmm15, 0xB1 pshufhw xmm15, xmm15, 0xB1 pshuflw xmm12, xmm12, 0xB1 pshufhw xmm12, xmm12, 0xB1 pshuflw xmm13, xmm13, 0xB1 pshufhw xmm13, xmm13, 0xB1 pshuflw xmm14, xmm14, 0xB1 pshufhw xmm14, xmm14, 0xB1 paddd xmm10, xmm15 paddd xmm11, xmm12 movdqa xmm8, xmmword ptr [rsp+0x100] paddd xmm8, xmm13 paddd xmm9, xmm14 pxor xmm5, xmm10 pxor xmm6, xmm11 pxor xmm7, xmm8 pxor xmm4, xmm9 movdqa xmmword ptr [rsp+0x100], xmm8 movdqa xmm8, xmm5 psrld xmm8, 12 pslld xmm5, 20 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 12 pslld xmm6, 20 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 12 pslld xmm7, 20 por xmm7, xmm8 movdqa xmm8, xmm4 psrld xmm8, 12 pslld xmm4, 20 por xmm4, xmm8 paddd xmm0, xmmword ptr [rsp+0xA0] paddd xmm1, xmmword ptr [rsp+0xC0] paddd xmm2, xmmword ptr [rsp+0x40] paddd xmm3, xmmword ptr [rsp+0xD0] paddd xmm0, xmm5 paddd xmm1, xmm6 paddd xmm2, xmm7 paddd xmm3, xmm4 pxor xmm15, xmm0 pxor xmm12, xmm1 pxor xmm13, xmm2 pxor xmm14, xmm3 movdqa xmm8, xmm15 psrld xmm15, 8 pslld xmm8, 24 pxor xmm15, xmm8 movdqa xmm8, xmm12 psrld xmm12, 8 pslld xmm8, 24 pxor xmm12, xmm8 movdqa xmm8, xmm13 psrld xmm13, 8 pslld xmm8, 24 pxor xmm13, xmm8 movdqa xmm8, xmm14 psrld xmm14, 8 pslld xmm8, 24 pxor xmm14, xmm8 paddd xmm10, xmm15 paddd xmm11, xmm12 movdqa xmm8, xmmword ptr [rsp+0x100] paddd xmm8, xmm13 paddd xmm9, xmm14 pxor xmm5, xmm10 pxor xmm6, xmm11 pxor xmm7, xmm8 pxor xmm4, xmm9 pxor xmm0, xmm8 pxor xmm1, xmm9 pxor xmm2, xmm10 pxor xmm3, xmm11 movdqa xmm8, xmm5 psrld xmm8, 7 pslld xmm5, 25 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 7 pslld xmm6, 25 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 7 pslld xmm7, 25 por xmm7, xmm8 movdqa xmm8, xmm4 psrld xmm8, 7 pslld xmm4, 25 por xmm4, xmm8 pxor xmm4, xmm12 pxor xmm5, xmm13 pxor xmm6, xmm14 pxor xmm7, xmm15 mov eax, r13d jne 9b movdqa xmm9, xmm0 punpckldq xmm0, xmm1 punpckhdq xmm9, xmm1 movdqa xmm11, xmm2 punpckldq xmm2, xmm3 punpckhdq xmm11, xmm3 movdqa xmm1, xmm0 punpcklqdq xmm0, xmm2 punpckhqdq xmm1, xmm2 movdqa xmm3, xmm9 punpcklqdq xmm9, xmm11 punpckhqdq xmm3, xmm11 movdqu xmmword ptr [rbx], xmm0 movdqu xmmword ptr [rbx+0x20], xmm1 movdqu xmmword ptr [rbx+0x40], xmm9 movdqu xmmword ptr [rbx+0x60], xmm3 movdqa xmm9, xmm4 punpckldq xmm4, xmm5 punpckhdq xmm9, xmm5 movdqa xmm11, xmm6 punpckldq xmm6, xmm7 punpckhdq xmm11, xmm7 movdqa xmm5, xmm4 punpcklqdq xmm4, xmm6 punpckhqdq xmm5, xmm6 movdqa xmm7, xmm9 punpcklqdq xmm9, xmm11 punpckhqdq xmm7, xmm11 movdqu xmmword ptr [rbx+0x10], xmm4 movdqu xmmword ptr [rbx+0x30], xmm5 movdqu xmmword ptr [rbx+0x50], xmm9 movdqu xmmword ptr [rbx+0x70], xmm7 movdqa xmm1, xmmword ptr [rsp+0x110] movdqa xmm0, xmm1 paddd xmm1, xmmword ptr [rsp+0x150] movdqa xmmword ptr [rsp+0x110], xmm1 pxor xmm0, xmmword ptr [CMP_MSB_MASK+rip] pxor xmm1, xmmword ptr [CMP_MSB_MASK+rip] pcmpgtd xmm0, xmm1 movdqa xmm1, xmmword ptr [rsp+0x120] psubd xmm1, xmm0 movdqa xmmword ptr [rsp+0x120], xmm1 add rbx, 128 add rdi, 32 sub rsi, 4 cmp rsi, 4 jnc 2b test rsi, rsi jne 3f 4: movdqa xmm6, xmmword ptr [rsp+0x170] movdqa xmm7, xmmword ptr [rsp+0x180] movdqa xmm8, xmmword ptr [rsp+0x190] movdqa xmm9, xmmword ptr [rsp+0x1A0] movdqa xmm10, xmmword ptr [rsp+0x1B0] movdqa xmm11, xmmword ptr [rsp+0x1C0] movdqa xmm12, xmmword ptr [rsp+0x1D0] movdqa xmm13, xmmword ptr [rsp+0x1E0] movdqa xmm14, xmmword ptr [rsp+0x1F0] movdqa xmm15, xmmword ptr [rsp+0x200] mov rsp, rbp pop rbp pop rbx pop rdi pop rsi pop r12 pop r13 pop r14 pop r15 ret .p2align 5 3: test esi, 0x2 je 3f movups xmm0, xmmword ptr [rcx] movups xmm1, xmmword ptr [rcx+0x10] movaps xmm8, xmm0 movaps xmm9, xmm1 movd xmm13, dword ptr [rsp+0x110] movd xmm14, dword ptr [rsp+0x120] punpckldq xmm13, xmm14 movaps xmmword ptr [rsp], xmm13 movd xmm14, dword ptr [rsp+0x114] movd xmm13, dword ptr [rsp+0x124] punpckldq xmm14, xmm13 movaps xmmword ptr [rsp+0x10], xmm14 mov r8, qword ptr [rdi] mov r9, qword ptr [rdi+0x8] movzx eax, byte ptr [rbp+0x80] or eax, r13d xor edx, edx 2: mov r14d, eax or eax, r12d add rdx, 64 cmp rdx, r15 cmovne eax, r14d movaps xmm2, xmmword ptr [BLAKE3_IV+rip] movaps xmm10, xmm2 movups xmm4, xmmword ptr [r8+rdx-0x40] movups xmm5, xmmword ptr [r8+rdx-0x30] movaps xmm3, xmm4 shufps xmm4, xmm5, 136 shufps xmm3, xmm5, 221 movaps xmm5, xmm3 movups xmm6, xmmword ptr [r8+rdx-0x20] movups xmm7, xmmword ptr [r8+rdx-0x10] movaps xmm3, xmm6 shufps xmm6, xmm7, 136 pshufd xmm6, xmm6, 0x93 shufps xmm3, xmm7, 221 pshufd xmm7, xmm3, 0x93 movups xmm12, xmmword ptr [r9+rdx-0x40] movups xmm13, xmmword ptr [r9+rdx-0x30] movaps xmm11, xmm12 shufps xmm12, xmm13, 136 shufps xmm11, xmm13, 221 movaps xmm13, xmm11 movups xmm14, xmmword ptr [r9+rdx-0x20] movups xmm15, xmmword ptr [r9+rdx-0x10] movaps xmm11, xmm14 shufps xmm14, xmm15, 136 pshufd xmm14, xmm14, 0x93 shufps xmm11, xmm15, 221 pshufd xmm15, xmm11, 0x93 shl rax, 0x20 or rax, 0x40 movq xmm3, rax movdqa xmmword ptr [rsp+0x20], xmm3 movaps xmm3, xmmword ptr [rsp] movaps xmm11, xmmword ptr [rsp+0x10] punpcklqdq xmm3, xmmword ptr [rsp+0x20] punpcklqdq xmm11, xmmword ptr [rsp+0x20] mov al, 7 9: paddd xmm0, xmm4 paddd xmm8, xmm12 movaps xmmword ptr [rsp+0x20], xmm4 movaps xmmword ptr [rsp+0x30], xmm12 paddd xmm0, xmm1 paddd xmm8, xmm9 pxor xmm3, xmm0 pxor xmm11, xmm8 pshuflw xmm3, xmm3, 0xB1 pshufhw xmm3, xmm3, 0xB1 pshuflw xmm11, xmm11, 0xB1 pshufhw xmm11, xmm11, 0xB1 paddd xmm2, xmm3 paddd xmm10, xmm11 pxor xmm1, xmm2 pxor xmm9, xmm10 movdqa xmm4, xmm1 pslld xmm1, 20 psrld xmm4, 12 por xmm1, xmm4 movdqa xmm4, xmm9 pslld xmm9, 20 psrld xmm4, 12 por xmm9, xmm4 paddd xmm0, xmm5 paddd xmm8, xmm13 movaps xmmword ptr [rsp+0x40], xmm5 movaps xmmword ptr [rsp+0x50], xmm13 paddd xmm0, xmm1 paddd xmm8, xmm9 pxor xmm3, xmm0 pxor xmm11, xmm8 movdqa xmm13, xmm3 psrld xmm3, 8 pslld xmm13, 24 pxor xmm3, xmm13 movdqa xmm13, xmm11 psrld xmm11, 8 pslld xmm13, 24 pxor xmm11, xmm13 paddd xmm2, xmm3 paddd xmm10, xmm11 pxor xmm1, xmm2 pxor xmm9, xmm10 movdqa xmm4, xmm1 pslld xmm1, 25 psrld xmm4, 7 por xmm1, xmm4 movdqa xmm4, xmm9 pslld xmm9, 25 psrld xmm4, 7 por xmm9, xmm4 pshufd xmm0, xmm0, 0x93 pshufd xmm8, xmm8, 0x93 pshufd xmm3, xmm3, 0x4E pshufd xmm11, xmm11, 0x4E pshufd xmm2, xmm2, 0x39 pshufd xmm10, xmm10, 0x39 paddd xmm0, xmm6 paddd xmm8, xmm14 paddd xmm0, xmm1 paddd xmm8, xmm9 pxor xmm3, xmm0 pxor xmm11, xmm8 pshuflw xmm3, xmm3, 0xB1 pshufhw xmm3, xmm3, 0xB1 pshuflw xmm11, xmm11, 0xB1 pshufhw xmm11, xmm11, 0xB1 paddd xmm2, xmm3 paddd xmm10, xmm11 pxor xmm1, xmm2 pxor xmm9, xmm10 movdqa xmm4, xmm1 pslld xmm1, 20 psrld xmm4, 12 por xmm1, xmm4 movdqa xmm4, xmm9 pslld xmm9, 20 psrld xmm4, 12 por xmm9, xmm4 paddd xmm0, xmm7 paddd xmm8, xmm15 paddd xmm0, xmm1 paddd xmm8, xmm9 pxor xmm3, xmm0 pxor xmm11, xmm8 movdqa xmm13, xmm3 psrld xmm3, 8 pslld xmm13, 24 pxor xmm3, xmm13 movdqa xmm13, xmm11 psrld xmm11, 8 pslld xmm13, 24 pxor xmm11, xmm13 paddd xmm2, xmm3 paddd xmm10, xmm11 pxor xmm1, xmm2 pxor xmm9, xmm10 movdqa xmm4, xmm1 pslld xmm1, 25 psrld xmm4, 7 por xmm1, xmm4 movdqa xmm4, xmm9 pslld xmm9, 25 psrld xmm4, 7 por xmm9, xmm4 pshufd xmm0, xmm0, 0x39 pshufd xmm8, xmm8, 0x39 pshufd xmm3, xmm3, 0x4E pshufd xmm11, xmm11, 0x4E pshufd xmm2, xmm2, 0x93 pshufd xmm10, xmm10, 0x93 dec al je 9f movdqa xmm12, xmmword ptr [rsp+0x20] movdqa xmm5, xmmword ptr [rsp+0x40] pshufd xmm13, xmm12, 0x0F shufps xmm12, xmm5, 214 pshufd xmm4, xmm12, 0x39 movdqa xmm12, xmm6 shufps xmm12, xmm7, 250 pand xmm13, xmmword ptr [PBLENDW_0x33_MASK+rip] pand xmm12, xmmword ptr [PBLENDW_0xCC_MASK+rip] por xmm13, xmm12 movdqa xmmword ptr [rsp+0x20], xmm13 movdqa xmm12, xmm7 punpcklqdq xmm12, xmm5 movdqa xmm13, xmm6 pand xmm12, xmmword ptr [PBLENDW_0x3F_MASK+rip] pand xmm13, xmmword ptr [PBLENDW_0xC0_MASK+rip] por xmm12, xmm13 pshufd xmm12, xmm12, 0x78 punpckhdq xmm5, xmm7 punpckldq xmm6, xmm5 pshufd xmm7, xmm6, 0x1E movdqa xmmword ptr [rsp+0x40], xmm12 movdqa xmm5, xmmword ptr [rsp+0x30] movdqa xmm13, xmmword ptr [rsp+0x50] pshufd xmm6, xmm5, 0x0F shufps xmm5, xmm13, 214 pshufd xmm12, xmm5, 0x39 movdqa xmm5, xmm14 shufps xmm5, xmm15, 250 pand xmm6, xmmword ptr [PBLENDW_0x33_MASK+rip] pand xmm5, xmmword ptr [PBLENDW_0xCC_MASK+rip] por xmm6, xmm5 movdqa xmm5, xmm15 punpcklqdq xmm5, xmm13 movdqa xmmword ptr [rsp+0x30], xmm2 movdqa xmm2, xmm14 pand xmm5, xmmword ptr [PBLENDW_0x3F_MASK+rip] pand xmm2, xmmword ptr [PBLENDW_0xC0_MASK+rip] por xmm5, xmm2 movdqa xmm2, xmmword ptr [rsp+0x30] pshufd xmm5, xmm5, 0x78 punpckhdq xmm13, xmm15 punpckldq xmm14, xmm13 pshufd xmm15, xmm14, 0x1E movdqa xmm13, xmm6 movdqa xmm14, xmm5 movdqa xmm5, xmmword ptr [rsp+0x20] movdqa xmm6, xmmword ptr [rsp+0x40] jmp 9b 9: pxor xmm0, xmm2 pxor xmm1, xmm3 pxor xmm8, xmm10 pxor xmm9, xmm11 mov eax, r13d cmp rdx, r15 jne 2b movups xmmword ptr [rbx], xmm0 movups xmmword ptr [rbx+0x10], xmm1 movups xmmword ptr [rbx+0x20], xmm8 movups xmmword ptr [rbx+0x30], xmm9 mov eax, dword ptr [rsp+0x130] neg eax mov r10d, dword ptr [rsp+0x110+8*rax] mov r11d, dword ptr [rsp+0x120+8*rax] mov dword ptr [rsp+0x110], r10d mov dword ptr [rsp+0x120], r11d add rdi, 16 add rbx, 64 sub rsi, 2 3: test esi, 0x1 je 4b movups xmm0, xmmword ptr [rcx] movups xmm1, xmmword ptr [rcx+0x10] movd xmm13, dword ptr [rsp+0x110] movd xmm14, dword ptr [rsp+0x120] punpckldq xmm13, xmm14 mov r8, qword ptr [rdi] movzx eax, byte ptr [rbp+0x80] or eax, r13d xor edx, edx 2: mov r14d, eax or eax, r12d add rdx, 64 cmp rdx, r15 cmovne eax, r14d movaps xmm2, xmmword ptr [BLAKE3_IV+rip] shl rax, 32 or rax, 64 movq xmm12, rax movdqa xmm3, xmm13 punpcklqdq xmm3, xmm12 movups xmm4, xmmword ptr [r8+rdx-0x40] movups xmm5, xmmword ptr [r8+rdx-0x30] movaps xmm8, xmm4 shufps xmm4, xmm5, 136 shufps xmm8, xmm5, 221 movaps xmm5, xmm8 movups xmm6, xmmword ptr [r8+rdx-0x20] movups xmm7, xmmword ptr [r8+rdx-0x10] movaps xmm8, xmm6 shufps xmm6, xmm7, 136 pshufd xmm6, xmm6, 0x93 shufps xmm8, xmm7, 221 pshufd xmm7, xmm8, 0x93 mov al, 7 9: paddd xmm0, xmm4 paddd xmm0, xmm1 pxor xmm3, xmm0 pshuflw xmm3, xmm3, 0xB1 pshufhw xmm3, xmm3, 0xB1 paddd xmm2, xmm3 pxor xmm1, xmm2 movdqa xmm11, xmm1 pslld xmm1, 20 psrld xmm11, 12 por xmm1, xmm11 paddd xmm0, xmm5 paddd xmm0, xmm1 pxor xmm3, xmm0 movdqa xmm14, xmm3 psrld xmm3, 8 pslld xmm14, 24 pxor xmm3, xmm14 paddd xmm2, xmm3 pxor xmm1, xmm2 movdqa xmm11, xmm1 pslld xmm1, 25 psrld xmm11, 7 por xmm1, xmm11 pshufd xmm0, xmm0, 0x93 pshufd xmm3, xmm3, 0x4E pshufd xmm2, xmm2, 0x39 paddd xmm0, xmm6 paddd xmm0, xmm1 pxor xmm3, xmm0 pshuflw xmm3, xmm3, 0xB1 pshufhw xmm3, xmm3, 0xB1 paddd xmm2, xmm3 pxor xmm1, xmm2 movdqa xmm11, xmm1 pslld xmm1, 20 psrld xmm11, 12 por xmm1, xmm11 paddd xmm0, xmm7 paddd xmm0, xmm1 pxor xmm3, xmm0 movdqa xmm14, xmm3 psrld xmm3, 8 pslld xmm14, 24 pxor xmm3, xmm14 paddd xmm2, xmm3 pxor xmm1, xmm2 movdqa xmm11, xmm1 pslld xmm1, 25 psrld xmm11, 7 por xmm1, xmm11 pshufd xmm0, xmm0, 0x39 pshufd xmm3, xmm3, 0x4E pshufd xmm2, xmm2, 0x93 dec al jz 9f movdqa xmm8, xmm4 shufps xmm8, xmm5, 214 pshufd xmm9, xmm4, 0x0F pshufd xmm4, xmm8, 0x39 movdqa xmm8, xmm6 shufps xmm8, xmm7, 250 pand xmm9, xmmword ptr [PBLENDW_0x33_MASK+rip] pand xmm8, xmmword ptr [PBLENDW_0xCC_MASK+rip] por xmm9, xmm8 movdqa xmm8, xmm7 punpcklqdq xmm8, xmm5 movdqa xmm10, xmm6 pand xmm8, xmmword ptr [PBLENDW_0x3F_MASK+rip] pand xmm10, xmmword ptr [PBLENDW_0xC0_MASK+rip] por xmm8, xmm10 pshufd xmm8, xmm8, 0x78 punpckhdq xmm5, xmm7 punpckldq xmm6, xmm5 pshufd xmm7, xmm6, 0x1E movdqa xmm5, xmm9 movdqa xmm6, xmm8 jmp 9b 9: pxor xmm0, xmm2 pxor xmm1, xmm3 mov eax, r13d cmp rdx, r15 jne 2b movups xmmword ptr [rbx], xmm0 movups xmmword ptr [rbx+0x10], xmm1 jmp 4b .p2align 6 blake3_compress_in_place_sse2: _blake3_compress_in_place_sse2: sub rsp, 120 movdqa xmmword ptr [rsp], xmm6 movdqa xmmword ptr [rsp+0x10], xmm7 movdqa xmmword ptr [rsp+0x20], xmm8 movdqa xmmword ptr [rsp+0x30], xmm9 movdqa xmmword ptr [rsp+0x40], xmm11 movdqa xmmword ptr [rsp+0x50], xmm14 movdqa xmmword ptr [rsp+0x60], xmm15 movups xmm0, xmmword ptr [rcx] movups xmm1, xmmword ptr [rcx+0x10] movaps xmm2, xmmword ptr [BLAKE3_IV+rip] movzx eax, byte ptr [rsp+0xA0] movzx r8d, r8b shl rax, 32 add r8, rax movq xmm3, r9 movq xmm4, r8 punpcklqdq xmm3, xmm4 movups xmm4, xmmword ptr [rdx] movups xmm5, xmmword ptr [rdx+0x10] movaps xmm8, xmm4 shufps xmm4, xmm5, 136 shufps xmm8, xmm5, 221 movaps xmm5, xmm8 movups xmm6, xmmword ptr [rdx+0x20] movups xmm7, xmmword ptr [rdx+0x30] movaps xmm8, xmm6 shufps xmm6, xmm7, 136 pshufd xmm6, xmm6, 0x93 shufps xmm8, xmm7, 221 pshufd xmm7, xmm8, 0x93 mov al, 7 9: paddd xmm0, xmm4 paddd xmm0, xmm1 pxor xmm3, xmm0 pshuflw xmm3, xmm3, 0xB1 pshufhw xmm3, xmm3, 0xB1 paddd xmm2, xmm3 pxor xmm1, xmm2 movdqa xmm11, xmm1 pslld xmm1, 20 psrld xmm11, 12 por xmm1, xmm11 paddd xmm0, xmm5 paddd xmm0, xmm1 pxor xmm3, xmm0 movdqa xmm14, xmm3 psrld xmm3, 8 pslld xmm14, 24 pxor xmm3, xmm14 paddd xmm2, xmm3 pxor xmm1, xmm2 movdqa xmm11, xmm1 pslld xmm1, 25 psrld xmm11, 7 por xmm1, xmm11 pshufd xmm0, xmm0, 0x93 pshufd xmm3, xmm3, 0x4E pshufd xmm2, xmm2, 0x39 paddd xmm0, xmm6 paddd xmm0, xmm1 pxor xmm3, xmm0 pshuflw xmm3, xmm3, 0xB1 pshufhw xmm3, xmm3, 0xB1 paddd xmm2, xmm3 pxor xmm1, xmm2 movdqa xmm11, xmm1 pslld xmm1, 20 psrld xmm11, 12 por xmm1, xmm11 paddd xmm0, xmm7 paddd xmm0, xmm1 pxor xmm3, xmm0 movdqa xmm14, xmm3 psrld xmm3, 8 pslld xmm14, 24 pxor xmm3, xmm14 paddd xmm2, xmm3 pxor xmm1, xmm2 movdqa xmm11, xmm1 pslld xmm1, 25 psrld xmm11, 7 por xmm1, xmm11 pshufd xmm0, xmm0, 0x39 pshufd xmm3, xmm3, 0x4E pshufd xmm2, xmm2, 0x93 dec al jz 9f movdqa xmm8, xmm4 shufps xmm8, xmm5, 214 pshufd xmm9, xmm4, 0x0F pshufd xmm4, xmm8, 0x39 movdqa xmm8, xmm6 shufps xmm8, xmm7, 250 pand xmm9, xmmword ptr [PBLENDW_0x33_MASK+rip] pand xmm8, xmmword ptr [PBLENDW_0xCC_MASK+rip] por xmm9, xmm8 movdqa xmm8, xmm7 punpcklqdq xmm8, xmm5 movdqa xmm14, xmm6 pand xmm8, xmmword ptr [PBLENDW_0x3F_MASK+rip] pand xmm14, xmmword ptr [PBLENDW_0xC0_MASK+rip] por xmm8, xmm14 pshufd xmm8, xmm8, 0x78 punpckhdq xmm5, xmm7 punpckldq xmm6, xmm5 pshufd xmm7, xmm6, 0x1E movdqa xmm5, xmm9 movdqa xmm6, xmm8 jmp 9b 9: pxor xmm0, xmm2 pxor xmm1, xmm3 movups xmmword ptr [rcx], xmm0 movups xmmword ptr [rcx+0x10], xmm1 movdqa xmm6, xmmword ptr [rsp] movdqa xmm7, xmmword ptr [rsp+0x10] movdqa xmm8, xmmword ptr [rsp+0x20] movdqa xmm9, xmmword ptr [rsp+0x30] movdqa xmm11, xmmword ptr [rsp+0x40] movdqa xmm14, xmmword ptr [rsp+0x50] movdqa xmm15, xmmword ptr [rsp+0x60] add rsp, 120 ret .p2align 6 _blake3_compress_xof_sse2: blake3_compress_xof_sse2: sub rsp, 120 movdqa xmmword ptr [rsp], xmm6 movdqa xmmword ptr [rsp+0x10], xmm7 movdqa xmmword ptr [rsp+0x20], xmm8 movdqa xmmword ptr [rsp+0x30], xmm9 movdqa xmmword ptr [rsp+0x40], xmm11 movdqa xmmword ptr [rsp+0x50], xmm14 movdqa xmmword ptr [rsp+0x60], xmm15 movups xmm0, xmmword ptr [rcx] movups xmm1, xmmword ptr [rcx+0x10] movaps xmm2, xmmword ptr [BLAKE3_IV+rip] movzx eax, byte ptr [rsp+0xA0] movzx r8d, r8b mov r10, qword ptr [rsp+0xA8] shl rax, 32 add r8, rax movq xmm3, r9 movq xmm4, r8 punpcklqdq xmm3, xmm4 movups xmm4, xmmword ptr [rdx] movups xmm5, xmmword ptr [rdx+0x10] movaps xmm8, xmm4 shufps xmm4, xmm5, 136 shufps xmm8, xmm5, 221 movaps xmm5, xmm8 movups xmm6, xmmword ptr [rdx+0x20] movups xmm7, xmmword ptr [rdx+0x30] movaps xmm8, xmm6 shufps xmm6, xmm7, 136 pshufd xmm6, xmm6, 0x93 shufps xmm8, xmm7, 221 pshufd xmm7, xmm8, 0x93 mov al, 7 9: paddd xmm0, xmm4 paddd xmm0, xmm1 pxor xmm3, xmm0 pshuflw xmm3, xmm3, 0xB1 pshufhw xmm3, xmm3, 0xB1 paddd xmm2, xmm3 pxor xmm1, xmm2 movdqa xmm11, xmm1 pslld xmm1, 20 psrld xmm11, 12 por xmm1, xmm11 paddd xmm0, xmm5 paddd xmm0, xmm1 pxor xmm3, xmm0 movdqa xmm14, xmm3 psrld xmm3, 8 pslld xmm14, 24 pxor xmm3, xmm14 paddd xmm2, xmm3 pxor xmm1, xmm2 movdqa xmm11, xmm1 pslld xmm1, 25 psrld xmm11, 7 por xmm1, xmm11 pshufd xmm0, xmm0, 0x93 pshufd xmm3, xmm3, 0x4E pshufd xmm2, xmm2, 0x39 paddd xmm0, xmm6 paddd xmm0, xmm1 pxor xmm3, xmm0 pshuflw xmm3, xmm3, 0xB1 pshufhw xmm3, xmm3, 0xB1 paddd xmm2, xmm3 pxor xmm1, xmm2 movdqa xmm11, xmm1 pslld xmm1, 20 psrld xmm11, 12 por xmm1, xmm11 paddd xmm0, xmm7 paddd xmm0, xmm1 pxor xmm3, xmm0 movdqa xmm14, xmm3 psrld xmm3, 8 pslld xmm14, 24 pxor xmm3, xmm14 paddd xmm2, xmm3 pxor xmm1, xmm2 movdqa xmm11, xmm1 pslld xmm1, 25 psrld xmm11, 7 por xmm1, xmm11 pshufd xmm0, xmm0, 0x39 pshufd xmm3, xmm3, 0x4E pshufd xmm2, xmm2, 0x93 dec al jz 9f movdqa xmm8, xmm4 shufps xmm8, xmm5, 214 pshufd xmm9, xmm4, 0x0F pshufd xmm4, xmm8, 0x39 movdqa xmm8, xmm6 shufps xmm8, xmm7, 250 pand xmm9, xmmword ptr [PBLENDW_0x33_MASK+rip] pand xmm8, xmmword ptr [PBLENDW_0xCC_MASK+rip] por xmm9, xmm8 movdqa xmm8, xmm7 punpcklqdq xmm8, xmm5 movdqa xmm14, xmm6 pand xmm8, xmmword ptr [PBLENDW_0x3F_MASK+rip] pand xmm14, xmmword ptr [PBLENDW_0xC0_MASK+rip] por xmm8, xmm14 pshufd xmm8, xmm8, 0x78 punpckhdq xmm5, xmm7 punpckldq xmm6, xmm5 pshufd xmm7, xmm6, 0x1E movdqa xmm5, xmm9 movdqa xmm6, xmm8 jmp 9b 9: movdqu xmm4, xmmword ptr [rcx] movdqu xmm5, xmmword ptr [rcx+0x10] pxor xmm0, xmm2 pxor xmm1, xmm3 pxor xmm2, xmm4 pxor xmm3, xmm5 movups xmmword ptr [r10], xmm0 movups xmmword ptr [r10+0x10], xmm1 movups xmmword ptr [r10+0x20], xmm2 movups xmmword ptr [r10+0x30], xmm3 movdqa xmm6, xmmword ptr [rsp] movdqa xmm7, xmmword ptr [rsp+0x10] movdqa xmm8, xmmword ptr [rsp+0x20] movdqa xmm9, xmmword ptr [rsp+0x30] movdqa xmm11, xmmword ptr [rsp+0x40] movdqa xmm14, xmmword ptr [rsp+0x50] movdqa xmm15, xmmword ptr [rsp+0x60] add rsp, 120 ret .section .rdata .p2align 6 BLAKE3_IV: .long 0x6A09E667, 0xBB67AE85 .long 0x3C6EF372, 0xA54FF53A ADD0: .long 0, 1, 2, 3 ADD1: .long 4, 4, 4, 4 BLAKE3_IV_0: .long 0x6A09E667, 0x6A09E667, 0x6A09E667, 0x6A09E667 BLAKE3_IV_1: .long 0xBB67AE85, 0xBB67AE85, 0xBB67AE85, 0xBB67AE85 BLAKE3_IV_2: .long 0x3C6EF372, 0x3C6EF372, 0x3C6EF372, 0x3C6EF372 BLAKE3_IV_3: .long 0xA54FF53A, 0xA54FF53A, 0xA54FF53A, 0xA54FF53A BLAKE3_BLOCK_LEN: .long 64, 64, 64, 64 CMP_MSB_MASK: .long 0x80000000, 0x80000000, 0x80000000, 0x80000000 PBLENDW_0x33_MASK: .long 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000 PBLENDW_0xCC_MASK: .long 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF PBLENDW_0x3F_MASK: .long 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000 PBLENDW_0xC0_MASK: .long 0x00000000, 0x00000000, 0x00000000, 0xFFFFFFFF librecast/libs/blake3/c/blake3_sse2_x86-64_windows_msvc.asm000066400000000000000000002125061502456746400237220ustar00rootroot00000000000000public _blake3_hash_many_sse2 public blake3_hash_many_sse2 public blake3_compress_in_place_sse2 public _blake3_compress_in_place_sse2 public blake3_compress_xof_sse2 public _blake3_compress_xof_sse2 _TEXT SEGMENT ALIGN(16) 'CODE' ALIGN 16 blake3_hash_many_sse2 PROC _blake3_hash_many_sse2 PROC push r15 push r14 push r13 push r12 push rsi push rdi push rbx push rbp mov rbp, rsp sub rsp, 528 and rsp, 0FFFFFFFFFFFFFFC0H movdqa xmmword ptr [rsp+170H], xmm6 movdqa xmmword ptr [rsp+180H], xmm7 movdqa xmmword ptr [rsp+190H], xmm8 movdqa xmmword ptr [rsp+1A0H], xmm9 movdqa xmmword ptr [rsp+1B0H], xmm10 movdqa xmmword ptr [rsp+1C0H], xmm11 movdqa xmmword ptr [rsp+1D0H], xmm12 movdqa xmmword ptr [rsp+1E0H], xmm13 movdqa xmmword ptr [rsp+1F0H], xmm14 movdqa xmmword ptr [rsp+200H], xmm15 mov rdi, rcx mov rsi, rdx mov rdx, r8 mov rcx, r9 mov r8, qword ptr [rbp+68H] movzx r9, byte ptr [rbp+70H] neg r9d movd xmm0, r9d pshufd xmm0, xmm0, 00H movdqa xmmword ptr [rsp+130H], xmm0 movdqa xmm1, xmm0 pand xmm1, xmmword ptr [ADD0] pand xmm0, xmmword ptr [ADD1] movdqa xmmword ptr [rsp+150H], xmm0 movd xmm0, r8d pshufd xmm0, xmm0, 00H paddd xmm0, xmm1 movdqa xmmword ptr [rsp+110H], xmm0 pxor xmm0, xmmword ptr [CMP_MSB_MASK] pxor xmm1, xmmword ptr [CMP_MSB_MASK] pcmpgtd xmm1, xmm0 shr r8, 32 movd xmm2, r8d pshufd xmm2, xmm2, 00H psubd xmm2, xmm1 movdqa xmmword ptr [rsp+120H], xmm2 mov rbx, qword ptr [rbp+90H] mov r15, rdx shl r15, 6 movzx r13d, byte ptr [rbp+78H] movzx r12d, byte ptr [rbp+88H] cmp rsi, 4 jc final3blocks outerloop4: movdqu xmm3, xmmword ptr [rcx] pshufd xmm0, xmm3, 00H pshufd xmm1, xmm3, 55H pshufd xmm2, xmm3, 0AAH pshufd xmm3, xmm3, 0FFH movdqu xmm7, xmmword ptr [rcx+10H] pshufd xmm4, xmm7, 00H pshufd xmm5, xmm7, 55H pshufd xmm6, xmm7, 0AAH pshufd xmm7, xmm7, 0FFH mov r8, qword ptr [rdi] mov r9, qword ptr [rdi+8H] mov r10, qword ptr [rdi+10H] mov r11, qword ptr [rdi+18H] movzx eax, byte ptr [rbp+80H] or eax, r13d xor edx, edx innerloop4: mov r14d, eax or eax, r12d add rdx, 64 cmp rdx, r15 cmovne eax, r14d movdqu xmm8, xmmword ptr [r8+rdx-40H] movdqu xmm9, xmmword ptr [r9+rdx-40H] movdqu xmm10, xmmword ptr [r10+rdx-40H] movdqu xmm11, xmmword ptr [r11+rdx-40H] movdqa xmm12, xmm8 punpckldq xmm8, xmm9 punpckhdq xmm12, xmm9 movdqa xmm14, xmm10 punpckldq xmm10, xmm11 punpckhdq xmm14, xmm11 movdqa xmm9, xmm8 punpcklqdq xmm8, xmm10 punpckhqdq xmm9, xmm10 movdqa xmm13, xmm12 punpcklqdq xmm12, xmm14 punpckhqdq xmm13, xmm14 movdqa xmmword ptr [rsp], xmm8 movdqa xmmword ptr [rsp+10H], xmm9 movdqa xmmword ptr [rsp+20H], xmm12 movdqa xmmword ptr [rsp+30H], xmm13 movdqu xmm8, xmmword ptr [r8+rdx-30H] movdqu xmm9, xmmword ptr [r9+rdx-30H] movdqu xmm10, xmmword ptr [r10+rdx-30H] movdqu xmm11, xmmword ptr [r11+rdx-30H] movdqa xmm12, xmm8 punpckldq xmm8, xmm9 punpckhdq xmm12, xmm9 movdqa xmm14, xmm10 punpckldq xmm10, xmm11 punpckhdq xmm14, xmm11 movdqa xmm9, xmm8 punpcklqdq xmm8, xmm10 punpckhqdq xmm9, xmm10 movdqa xmm13, xmm12 punpcklqdq xmm12, xmm14 punpckhqdq xmm13, xmm14 movdqa xmmword ptr [rsp+40H], xmm8 movdqa xmmword ptr [rsp+50H], xmm9 movdqa xmmword ptr [rsp+60H], xmm12 movdqa xmmword ptr [rsp+70H], xmm13 movdqu xmm8, xmmword ptr [r8+rdx-20H] movdqu xmm9, xmmword ptr [r9+rdx-20H] movdqu xmm10, xmmword ptr [r10+rdx-20H] movdqu xmm11, xmmword ptr [r11+rdx-20H] movdqa xmm12, xmm8 punpckldq xmm8, xmm9 punpckhdq xmm12, xmm9 movdqa xmm14, xmm10 punpckldq xmm10, xmm11 punpckhdq xmm14, xmm11 movdqa xmm9, xmm8 punpcklqdq xmm8, xmm10 punpckhqdq xmm9, xmm10 movdqa xmm13, xmm12 punpcklqdq xmm12, xmm14 punpckhqdq xmm13, xmm14 movdqa xmmword ptr [rsp+80H], xmm8 movdqa xmmword ptr [rsp+90H], xmm9 movdqa xmmword ptr [rsp+0A0H], xmm12 movdqa xmmword ptr [rsp+0B0H], xmm13 movdqu xmm8, xmmword ptr [r8+rdx-10H] movdqu xmm9, xmmword ptr [r9+rdx-10H] movdqu xmm10, xmmword ptr [r10+rdx-10H] movdqu xmm11, xmmword ptr [r11+rdx-10H] movdqa xmm12, xmm8 punpckldq xmm8, xmm9 punpckhdq xmm12, xmm9 movdqa xmm14, xmm10 punpckldq xmm10, xmm11 punpckhdq xmm14, xmm11 movdqa xmm9, xmm8 punpcklqdq xmm8, xmm10 punpckhqdq xmm9, xmm10 movdqa xmm13, xmm12 punpcklqdq xmm12, xmm14 punpckhqdq xmm13, xmm14 movdqa xmmword ptr [rsp+0C0H], xmm8 movdqa xmmword ptr [rsp+0D0H], xmm9 movdqa xmmword ptr [rsp+0E0H], xmm12 movdqa xmmword ptr [rsp+0F0H], xmm13 movdqa xmm9, xmmword ptr [BLAKE3_IV_1] movdqa xmm10, xmmword ptr [BLAKE3_IV_2] movdqa xmm11, xmmword ptr [BLAKE3_IV_3] movdqa xmm12, xmmword ptr [rsp+110H] movdqa xmm13, xmmword ptr [rsp+120H] movdqa xmm14, xmmword ptr [BLAKE3_BLOCK_LEN] movd xmm15, eax pshufd xmm15, xmm15, 00H prefetcht0 byte ptr [r8+rdx+80H] prefetcht0 byte ptr [r9+rdx+80H] prefetcht0 byte ptr [r10+rdx+80H] prefetcht0 byte ptr [r11+rdx+80H] paddd xmm0, xmmword ptr [rsp] paddd xmm1, xmmword ptr [rsp+20H] paddd xmm2, xmmword ptr [rsp+40H] paddd xmm3, xmmword ptr [rsp+60H] paddd xmm0, xmm4 paddd xmm1, xmm5 paddd xmm2, xmm6 paddd xmm3, xmm7 pxor xmm12, xmm0 pxor xmm13, xmm1 pxor xmm14, xmm2 pxor xmm15, xmm3 pshuflw xmm12, xmm12, 0B1H pshufhw xmm12, xmm12, 0B1H pshuflw xmm13, xmm13, 0B1H pshufhw xmm13, xmm13, 0B1H pshuflw xmm14, xmm14, 0B1H pshufhw xmm14, xmm14, 0B1H pshuflw xmm15, xmm15, 0B1H pshufhw xmm15, xmm15, 0B1H movdqa xmm8, xmmword ptr [BLAKE3_IV_0] paddd xmm8, xmm12 paddd xmm9, xmm13 paddd xmm10, xmm14 paddd xmm11, xmm15 pxor xmm4, xmm8 pxor xmm5, xmm9 pxor xmm6, xmm10 pxor xmm7, xmm11 movdqa xmmword ptr [rsp+100H], xmm8 movdqa xmm8, xmm4 psrld xmm8, 12 pslld xmm4, 20 por xmm4, xmm8 movdqa xmm8, xmm5 psrld xmm8, 12 pslld xmm5, 20 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 12 pslld xmm6, 20 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 12 pslld xmm7, 20 por xmm7, xmm8 paddd xmm0, xmmword ptr [rsp+10H] paddd xmm1, xmmword ptr [rsp+30H] paddd xmm2, xmmword ptr [rsp+50H] paddd xmm3, xmmword ptr [rsp+70H] paddd xmm0, xmm4 paddd xmm1, xmm5 paddd xmm2, xmm6 paddd xmm3, xmm7 pxor xmm12, xmm0 pxor xmm13, xmm1 pxor xmm14, xmm2 pxor xmm15, xmm3 movdqa xmm8, xmm12 psrld xmm12, 8 pslld xmm8, 24 pxor xmm12, xmm8 movdqa xmm8, xmm13 psrld xmm13, 8 pslld xmm8, 24 pxor xmm13, xmm8 movdqa xmm8, xmm14 psrld xmm14, 8 pslld xmm8, 24 pxor xmm14, xmm8 movdqa xmm8, xmm15 psrld xmm15, 8 pslld xmm8, 24 pxor xmm15, xmm8 movdqa xmm8, xmmword ptr [rsp+100H] paddd xmm8, xmm12 paddd xmm9, xmm13 paddd xmm10, xmm14 paddd xmm11, xmm15 pxor xmm4, xmm8 pxor xmm5, xmm9 pxor xmm6, xmm10 pxor xmm7, xmm11 movdqa xmmword ptr [rsp+100H], xmm8 movdqa xmm8, xmm4 psrld xmm8, 7 pslld xmm4, 25 por xmm4, xmm8 movdqa xmm8, xmm5 psrld xmm8, 7 pslld xmm5, 25 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 7 pslld xmm6, 25 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 7 pslld xmm7, 25 por xmm7, xmm8 paddd xmm0, xmmword ptr [rsp+80H] paddd xmm1, xmmword ptr [rsp+0A0H] paddd xmm2, xmmword ptr [rsp+0C0H] paddd xmm3, xmmword ptr [rsp+0E0H] paddd xmm0, xmm5 paddd xmm1, xmm6 paddd xmm2, xmm7 paddd xmm3, xmm4 pxor xmm15, xmm0 pxor xmm12, xmm1 pxor xmm13, xmm2 pxor xmm14, xmm3 pshuflw xmm15, xmm15, 0B1H pshufhw xmm15, xmm15, 0B1H pshuflw xmm12, xmm12, 0B1H pshufhw xmm12, xmm12, 0B1H pshuflw xmm13, xmm13, 0B1H pshufhw xmm13, xmm13, 0B1H pshuflw xmm14, xmm14, 0B1H pshufhw xmm14, xmm14, 0B1H paddd xmm10, xmm15 paddd xmm11, xmm12 movdqa xmm8, xmmword ptr [rsp+100H] paddd xmm8, xmm13 paddd xmm9, xmm14 pxor xmm5, xmm10 pxor xmm6, xmm11 pxor xmm7, xmm8 pxor xmm4, xmm9 movdqa xmmword ptr [rsp+100H], xmm8 movdqa xmm8, xmm5 psrld xmm8, 12 pslld xmm5, 20 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 12 pslld xmm6, 20 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 12 pslld xmm7, 20 por xmm7, xmm8 movdqa xmm8, xmm4 psrld xmm8, 12 pslld xmm4, 20 por xmm4, xmm8 paddd xmm0, xmmword ptr [rsp+90H] paddd xmm1, xmmword ptr [rsp+0B0H] paddd xmm2, xmmword ptr [rsp+0D0H] paddd xmm3, xmmword ptr [rsp+0F0H] paddd xmm0, xmm5 paddd xmm1, xmm6 paddd xmm2, xmm7 paddd xmm3, xmm4 pxor xmm15, xmm0 pxor xmm12, xmm1 pxor xmm13, xmm2 pxor xmm14, xmm3 movdqa xmm8, xmm15 psrld xmm15, 8 pslld xmm8, 24 pxor xmm15, xmm8 movdqa xmm8, xmm12 psrld xmm12, 8 pslld xmm8, 24 pxor xmm12, xmm8 movdqa xmm8, xmm13 psrld xmm13, 8 pslld xmm8, 24 pxor xmm13, xmm8 movdqa xmm8, xmm14 psrld xmm14, 8 pslld xmm8, 24 pxor xmm14, xmm8 paddd xmm10, xmm15 paddd xmm11, xmm12 movdqa xmm8, xmmword ptr [rsp+100H] paddd xmm8, xmm13 paddd xmm9, xmm14 pxor xmm5, xmm10 pxor xmm6, xmm11 pxor xmm7, xmm8 pxor xmm4, xmm9 movdqa xmmword ptr [rsp+100H], xmm8 movdqa xmm8, xmm5 psrld xmm8, 7 pslld xmm5, 25 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 7 pslld xmm6, 25 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 7 pslld xmm7, 25 por xmm7, xmm8 movdqa xmm8, xmm4 psrld xmm8, 7 pslld xmm4, 25 por xmm4, xmm8 paddd xmm0, xmmword ptr [rsp+20H] paddd xmm1, xmmword ptr [rsp+30H] paddd xmm2, xmmword ptr [rsp+70H] paddd xmm3, xmmword ptr [rsp+40H] paddd xmm0, xmm4 paddd xmm1, xmm5 paddd xmm2, xmm6 paddd xmm3, xmm7 pxor xmm12, xmm0 pxor xmm13, xmm1 pxor xmm14, xmm2 pxor xmm15, xmm3 pshuflw xmm12, xmm12, 0B1H pshufhw xmm12, xmm12, 0B1H pshuflw xmm13, xmm13, 0B1H pshufhw xmm13, xmm13, 0B1H pshuflw xmm14, xmm14, 0B1H pshufhw xmm14, xmm14, 0B1H pshuflw xmm15, xmm15, 0B1H pshufhw xmm15, xmm15, 0B1H movdqa xmm8, xmmword ptr [rsp+100H] paddd xmm8, xmm12 paddd xmm9, xmm13 paddd xmm10, xmm14 paddd xmm11, xmm15 pxor xmm4, xmm8 pxor xmm5, xmm9 pxor xmm6, xmm10 pxor xmm7, xmm11 movdqa xmmword ptr [rsp+100H], xmm8 movdqa xmm8, xmm4 psrld xmm8, 12 pslld xmm4, 20 por xmm4, xmm8 movdqa xmm8, xmm5 psrld xmm8, 12 pslld xmm5, 20 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 12 pslld xmm6, 20 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 12 pslld xmm7, 20 por xmm7, xmm8 paddd xmm0, xmmword ptr [rsp+60H] paddd xmm1, xmmword ptr [rsp+0A0H] paddd xmm2, xmmword ptr [rsp] paddd xmm3, xmmword ptr [rsp+0D0H] paddd xmm0, xmm4 paddd xmm1, xmm5 paddd xmm2, xmm6 paddd xmm3, xmm7 pxor xmm12, xmm0 pxor xmm13, xmm1 pxor xmm14, xmm2 pxor xmm15, xmm3 movdqa xmm8, xmm12 psrld xmm12, 8 pslld xmm8, 24 pxor xmm12, xmm8 movdqa xmm8, xmm13 psrld xmm13, 8 pslld xmm8, 24 pxor xmm13, xmm8 movdqa xmm8, xmm14 psrld xmm14, 8 pslld xmm8, 24 pxor xmm14, xmm8 movdqa xmm8, xmm15 psrld xmm15, 8 pslld xmm8, 24 pxor xmm15, xmm8 movdqa xmm8, xmmword ptr [rsp+100H] paddd xmm8, xmm12 paddd xmm9, xmm13 paddd xmm10, xmm14 paddd xmm11, xmm15 pxor xmm4, xmm8 pxor xmm5, xmm9 pxor xmm6, xmm10 pxor xmm7, xmm11 movdqa xmmword ptr [rsp+100H], xmm8 movdqa xmm8, xmm4 psrld xmm8, 7 pslld xmm4, 25 por xmm4, xmm8 movdqa xmm8, xmm5 psrld xmm8, 7 pslld xmm5, 25 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 7 pslld xmm6, 25 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 7 pslld xmm7, 25 por xmm7, xmm8 paddd xmm0, xmmword ptr [rsp+10H] paddd xmm1, xmmword ptr [rsp+0C0H] paddd xmm2, xmmword ptr [rsp+90H] paddd xmm3, xmmword ptr [rsp+0F0H] paddd xmm0, xmm5 paddd xmm1, xmm6 paddd xmm2, xmm7 paddd xmm3, xmm4 pxor xmm15, xmm0 pxor xmm12, xmm1 pxor xmm13, xmm2 pxor xmm14, xmm3 pshuflw xmm15, xmm15, 0B1H pshufhw xmm15, xmm15, 0B1H pshuflw xmm12, xmm12, 0B1H pshufhw xmm12, xmm12, 0B1H pshuflw xmm13, xmm13, 0B1H pshufhw xmm13, xmm13, 0B1H pshuflw xmm14, xmm14, 0B1H pshufhw xmm14, xmm14, 0B1H paddd xmm10, xmm15 paddd xmm11, xmm12 movdqa xmm8, xmmword ptr [rsp+100H] paddd xmm8, xmm13 paddd xmm9, xmm14 pxor xmm5, xmm10 pxor xmm6, xmm11 pxor xmm7, xmm8 pxor xmm4, xmm9 movdqa xmmword ptr [rsp+100H], xmm8 movdqa xmm8, xmm5 psrld xmm8, 12 pslld xmm5, 20 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 12 pslld xmm6, 20 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 12 pslld xmm7, 20 por xmm7, xmm8 movdqa xmm8, xmm4 psrld xmm8, 12 pslld xmm4, 20 por xmm4, xmm8 paddd xmm0, xmmword ptr [rsp+0B0H] paddd xmm1, xmmword ptr [rsp+50H] paddd xmm2, xmmword ptr [rsp+0E0H] paddd xmm3, xmmword ptr [rsp+80H] paddd xmm0, xmm5 paddd xmm1, xmm6 paddd xmm2, xmm7 paddd xmm3, xmm4 pxor xmm15, xmm0 pxor xmm12, xmm1 pxor xmm13, xmm2 pxor xmm14, xmm3 movdqa xmm8, xmm15 psrld xmm15, 8 pslld xmm8, 24 pxor xmm15, xmm8 movdqa xmm8, xmm12 psrld xmm12, 8 pslld xmm8, 24 pxor xmm12, xmm8 movdqa xmm8, xmm13 psrld xmm13, 8 pslld xmm8, 24 pxor xmm13, xmm8 movdqa xmm8, xmm14 psrld xmm14, 8 pslld xmm8, 24 pxor xmm14, xmm8 paddd xmm10, xmm15 paddd xmm11, xmm12 movdqa xmm8, xmmword ptr [rsp+100H] paddd xmm8, xmm13 paddd xmm9, xmm14 pxor xmm5, xmm10 pxor xmm6, xmm11 pxor xmm7, xmm8 pxor xmm4, xmm9 movdqa xmmword ptr [rsp+100H], xmm8 movdqa xmm8, xmm5 psrld xmm8, 7 pslld xmm5, 25 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 7 pslld xmm6, 25 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 7 pslld xmm7, 25 por xmm7, xmm8 movdqa xmm8, xmm4 psrld xmm8, 7 pslld xmm4, 25 por xmm4, xmm8 paddd xmm0, xmmword ptr [rsp+30H] paddd xmm1, xmmword ptr [rsp+0A0H] paddd xmm2, xmmword ptr [rsp+0D0H] paddd xmm3, xmmword ptr [rsp+70H] paddd xmm0, xmm4 paddd xmm1, xmm5 paddd xmm2, xmm6 paddd xmm3, xmm7 pxor xmm12, xmm0 pxor xmm13, xmm1 pxor xmm14, xmm2 pxor xmm15, xmm3 pshuflw xmm12, xmm12, 0B1H pshufhw xmm12, xmm12, 0B1H pshuflw xmm13, xmm13, 0B1H pshufhw xmm13, xmm13, 0B1H pshuflw xmm14, xmm14, 0B1H pshufhw xmm14, xmm14, 0B1H pshuflw xmm15, xmm15, 0B1H pshufhw xmm15, xmm15, 0B1H movdqa xmm8, xmmword ptr [rsp+100H] paddd xmm8, xmm12 paddd xmm9, xmm13 paddd xmm10, xmm14 paddd xmm11, xmm15 pxor xmm4, xmm8 pxor xmm5, xmm9 pxor xmm6, xmm10 pxor xmm7, xmm11 movdqa xmmword ptr [rsp+100H], xmm8 movdqa xmm8, xmm4 psrld xmm8, 12 pslld xmm4, 20 por xmm4, xmm8 movdqa xmm8, xmm5 psrld xmm8, 12 pslld xmm5, 20 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 12 pslld xmm6, 20 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 12 pslld xmm7, 20 por xmm7, xmm8 paddd xmm0, xmmword ptr [rsp+40H] paddd xmm1, xmmword ptr [rsp+0C0H] paddd xmm2, xmmword ptr [rsp+20H] paddd xmm3, xmmword ptr [rsp+0E0H] paddd xmm0, xmm4 paddd xmm1, xmm5 paddd xmm2, xmm6 paddd xmm3, xmm7 pxor xmm12, xmm0 pxor xmm13, xmm1 pxor xmm14, xmm2 pxor xmm15, xmm3 movdqa xmm8, xmm12 psrld xmm12, 8 pslld xmm8, 24 pxor xmm12, xmm8 movdqa xmm8, xmm13 psrld xmm13, 8 pslld xmm8, 24 pxor xmm13, xmm8 movdqa xmm8, xmm14 psrld xmm14, 8 pslld xmm8, 24 pxor xmm14, xmm8 movdqa xmm8, xmm15 psrld xmm15, 8 pslld xmm8, 24 pxor xmm15, xmm8 movdqa xmm8, xmmword ptr [rsp+100H] paddd xmm8, xmm12 paddd xmm9, xmm13 paddd xmm10, xmm14 paddd xmm11, xmm15 pxor xmm4, xmm8 pxor xmm5, xmm9 pxor xmm6, xmm10 pxor xmm7, xmm11 movdqa xmmword ptr [rsp+100H], xmm8 movdqa xmm8, xmm4 psrld xmm8, 7 pslld xmm4, 25 por xmm4, xmm8 movdqa xmm8, xmm5 psrld xmm8, 7 pslld xmm5, 25 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 7 pslld xmm6, 25 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 7 pslld xmm7, 25 por xmm7, xmm8 paddd xmm0, xmmword ptr [rsp+60H] paddd xmm1, xmmword ptr [rsp+90H] paddd xmm2, xmmword ptr [rsp+0B0H] paddd xmm3, xmmword ptr [rsp+80H] paddd xmm0, xmm5 paddd xmm1, xmm6 paddd xmm2, xmm7 paddd xmm3, xmm4 pxor xmm15, xmm0 pxor xmm12, xmm1 pxor xmm13, xmm2 pxor xmm14, xmm3 pshuflw xmm15, xmm15, 0B1H pshufhw xmm15, xmm15, 0B1H pshuflw xmm12, xmm12, 0B1H pshufhw xmm12, xmm12, 0B1H pshuflw xmm13, xmm13, 0B1H pshufhw xmm13, xmm13, 0B1H pshuflw xmm14, xmm14, 0B1H pshufhw xmm14, xmm14, 0B1H paddd xmm10, xmm15 paddd xmm11, xmm12 movdqa xmm8, xmmword ptr [rsp+100H] paddd xmm8, xmm13 paddd xmm9, xmm14 pxor xmm5, xmm10 pxor xmm6, xmm11 pxor xmm7, xmm8 pxor xmm4, xmm9 movdqa xmmword ptr [rsp+100H], xmm8 movdqa xmm8, xmm5 psrld xmm8, 12 pslld xmm5, 20 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 12 pslld xmm6, 20 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 12 pslld xmm7, 20 por xmm7, xmm8 movdqa xmm8, xmm4 psrld xmm8, 12 pslld xmm4, 20 por xmm4, xmm8 paddd xmm0, xmmword ptr [rsp+50H] paddd xmm1, xmmword ptr [rsp] paddd xmm2, xmmword ptr [rsp+0F0H] paddd xmm3, xmmword ptr [rsp+10H] paddd xmm0, xmm5 paddd xmm1, xmm6 paddd xmm2, xmm7 paddd xmm3, xmm4 pxor xmm15, xmm0 pxor xmm12, xmm1 pxor xmm13, xmm2 pxor xmm14, xmm3 movdqa xmm8, xmm15 psrld xmm15, 8 pslld xmm8, 24 pxor xmm15, xmm8 movdqa xmm8, xmm12 psrld xmm12, 8 pslld xmm8, 24 pxor xmm12, xmm8 movdqa xmm8, xmm13 psrld xmm13, 8 pslld xmm8, 24 pxor xmm13, xmm8 movdqa xmm8, xmm14 psrld xmm14, 8 pslld xmm8, 24 pxor xmm14, xmm8 paddd xmm10, xmm15 paddd xmm11, xmm12 movdqa xmm8, xmmword ptr [rsp+100H] paddd xmm8, xmm13 paddd xmm9, xmm14 pxor xmm5, xmm10 pxor xmm6, xmm11 pxor xmm7, xmm8 pxor xmm4, xmm9 movdqa xmmword ptr [rsp+100H], xmm8 movdqa xmm8, xmm5 psrld xmm8, 7 pslld xmm5, 25 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 7 pslld xmm6, 25 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 7 pslld xmm7, 25 por xmm7, xmm8 movdqa xmm8, xmm4 psrld xmm8, 7 pslld xmm4, 25 por xmm4, xmm8 paddd xmm0, xmmword ptr [rsp+0A0H] paddd xmm1, xmmword ptr [rsp+0C0H] paddd xmm2, xmmword ptr [rsp+0E0H] paddd xmm3, xmmword ptr [rsp+0D0H] paddd xmm0, xmm4 paddd xmm1, xmm5 paddd xmm2, xmm6 paddd xmm3, xmm7 pxor xmm12, xmm0 pxor xmm13, xmm1 pxor xmm14, xmm2 pxor xmm15, xmm3 pshuflw xmm12, xmm12, 0B1H pshufhw xmm12, xmm12, 0B1H pshuflw xmm13, xmm13, 0B1H pshufhw xmm13, xmm13, 0B1H pshuflw xmm14, xmm14, 0B1H pshufhw xmm14, xmm14, 0B1H pshuflw xmm15, xmm15, 0B1H pshufhw xmm15, xmm15, 0B1H movdqa xmm8, xmmword ptr [rsp+100H] paddd xmm8, xmm12 paddd xmm9, xmm13 paddd xmm10, xmm14 paddd xmm11, xmm15 pxor xmm4, xmm8 pxor xmm5, xmm9 pxor xmm6, xmm10 pxor xmm7, xmm11 movdqa xmmword ptr [rsp+100H], xmm8 movdqa xmm8, xmm4 psrld xmm8, 12 pslld xmm4, 20 por xmm4, xmm8 movdqa xmm8, xmm5 psrld xmm8, 12 pslld xmm5, 20 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 12 pslld xmm6, 20 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 12 pslld xmm7, 20 por xmm7, xmm8 paddd xmm0, xmmword ptr [rsp+70H] paddd xmm1, xmmword ptr [rsp+90H] paddd xmm2, xmmword ptr [rsp+30H] paddd xmm3, xmmword ptr [rsp+0F0H] paddd xmm0, xmm4 paddd xmm1, xmm5 paddd xmm2, xmm6 paddd xmm3, xmm7 pxor xmm12, xmm0 pxor xmm13, xmm1 pxor xmm14, xmm2 pxor xmm15, xmm3 movdqa xmm8, xmm12 psrld xmm12, 8 pslld xmm8, 24 pxor xmm12, xmm8 movdqa xmm8, xmm13 psrld xmm13, 8 pslld xmm8, 24 pxor xmm13, xmm8 movdqa xmm8, xmm14 psrld xmm14, 8 pslld xmm8, 24 pxor xmm14, xmm8 movdqa xmm8, xmm15 psrld xmm15, 8 pslld xmm8, 24 pxor xmm15, xmm8 movdqa xmm8, xmmword ptr [rsp+100H] paddd xmm8, xmm12 paddd xmm9, xmm13 paddd xmm10, xmm14 paddd xmm11, xmm15 pxor xmm4, xmm8 pxor xmm5, xmm9 pxor xmm6, xmm10 pxor xmm7, xmm11 movdqa xmmword ptr [rsp+100H], xmm8 movdqa xmm8, xmm4 psrld xmm8, 7 pslld xmm4, 25 por xmm4, xmm8 movdqa xmm8, xmm5 psrld xmm8, 7 pslld xmm5, 25 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 7 pslld xmm6, 25 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 7 pslld xmm7, 25 por xmm7, xmm8 paddd xmm0, xmmword ptr [rsp+40H] paddd xmm1, xmmword ptr [rsp+0B0H] paddd xmm2, xmmword ptr [rsp+50H] paddd xmm3, xmmword ptr [rsp+10H] paddd xmm0, xmm5 paddd xmm1, xmm6 paddd xmm2, xmm7 paddd xmm3, xmm4 pxor xmm15, xmm0 pxor xmm12, xmm1 pxor xmm13, xmm2 pxor xmm14, xmm3 pshuflw xmm15, xmm15, 0B1H pshufhw xmm15, xmm15, 0B1H pshuflw xmm12, xmm12, 0B1H pshufhw xmm12, xmm12, 0B1H pshuflw xmm13, xmm13, 0B1H pshufhw xmm13, xmm13, 0B1H pshuflw xmm14, xmm14, 0B1H pshufhw xmm14, xmm14, 0B1H paddd xmm10, xmm15 paddd xmm11, xmm12 movdqa xmm8, xmmword ptr [rsp+100H] paddd xmm8, xmm13 paddd xmm9, xmm14 pxor xmm5, xmm10 pxor xmm6, xmm11 pxor xmm7, xmm8 pxor xmm4, xmm9 movdqa xmmword ptr [rsp+100H], xmm8 movdqa xmm8, xmm5 psrld xmm8, 12 pslld xmm5, 20 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 12 pslld xmm6, 20 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 12 pslld xmm7, 20 por xmm7, xmm8 movdqa xmm8, xmm4 psrld xmm8, 12 pslld xmm4, 20 por xmm4, xmm8 paddd xmm0, xmmword ptr [rsp] paddd xmm1, xmmword ptr [rsp+20H] paddd xmm2, xmmword ptr [rsp+80H] paddd xmm3, xmmword ptr [rsp+60H] paddd xmm0, xmm5 paddd xmm1, xmm6 paddd xmm2, xmm7 paddd xmm3, xmm4 pxor xmm15, xmm0 pxor xmm12, xmm1 pxor xmm13, xmm2 pxor xmm14, xmm3 movdqa xmm8, xmm15 psrld xmm15, 8 pslld xmm8, 24 pxor xmm15, xmm8 movdqa xmm8, xmm12 psrld xmm12, 8 pslld xmm8, 24 pxor xmm12, xmm8 movdqa xmm8, xmm13 psrld xmm13, 8 pslld xmm8, 24 pxor xmm13, xmm8 movdqa xmm8, xmm14 psrld xmm14, 8 pslld xmm8, 24 pxor xmm14, xmm8 paddd xmm10, xmm15 paddd xmm11, xmm12 movdqa xmm8, xmmword ptr [rsp+100H] paddd xmm8, xmm13 paddd xmm9, xmm14 pxor xmm5, xmm10 pxor xmm6, xmm11 pxor xmm7, xmm8 pxor xmm4, xmm9 movdqa xmmword ptr [rsp+100H], xmm8 movdqa xmm8, xmm5 psrld xmm8, 7 pslld xmm5, 25 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 7 pslld xmm6, 25 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 7 pslld xmm7, 25 por xmm7, xmm8 movdqa xmm8, xmm4 psrld xmm8, 7 pslld xmm4, 25 por xmm4, xmm8 paddd xmm0, xmmword ptr [rsp+0C0H] paddd xmm1, xmmword ptr [rsp+90H] paddd xmm2, xmmword ptr [rsp+0F0H] paddd xmm3, xmmword ptr [rsp+0E0H] paddd xmm0, xmm4 paddd xmm1, xmm5 paddd xmm2, xmm6 paddd xmm3, xmm7 pxor xmm12, xmm0 pxor xmm13, xmm1 pxor xmm14, xmm2 pxor xmm15, xmm3 pshuflw xmm12, xmm12, 0B1H pshufhw xmm12, xmm12, 0B1H pshuflw xmm13, xmm13, 0B1H pshufhw xmm13, xmm13, 0B1H pshuflw xmm14, xmm14, 0B1H pshufhw xmm14, xmm14, 0B1H pshuflw xmm15, xmm15, 0B1H pshufhw xmm15, xmm15, 0B1H movdqa xmm8, xmmword ptr [rsp+100H] paddd xmm8, xmm12 paddd xmm9, xmm13 paddd xmm10, xmm14 paddd xmm11, xmm15 pxor xmm4, xmm8 pxor xmm5, xmm9 pxor xmm6, xmm10 pxor xmm7, xmm11 movdqa xmmword ptr [rsp+100H], xmm8 movdqa xmm8, xmm4 psrld xmm8, 12 pslld xmm4, 20 por xmm4, xmm8 movdqa xmm8, xmm5 psrld xmm8, 12 pslld xmm5, 20 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 12 pslld xmm6, 20 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 12 pslld xmm7, 20 por xmm7, xmm8 paddd xmm0, xmmword ptr [rsp+0D0H] paddd xmm1, xmmword ptr [rsp+0B0H] paddd xmm2, xmmword ptr [rsp+0A0H] paddd xmm3, xmmword ptr [rsp+80H] paddd xmm0, xmm4 paddd xmm1, xmm5 paddd xmm2, xmm6 paddd xmm3, xmm7 pxor xmm12, xmm0 pxor xmm13, xmm1 pxor xmm14, xmm2 pxor xmm15, xmm3 movdqa xmm8, xmm12 psrld xmm12, 8 pslld xmm8, 24 pxor xmm12, xmm8 movdqa xmm8, xmm13 psrld xmm13, 8 pslld xmm8, 24 pxor xmm13, xmm8 movdqa xmm8, xmm14 psrld xmm14, 8 pslld xmm8, 24 pxor xmm14, xmm8 movdqa xmm8, xmm15 psrld xmm15, 8 pslld xmm8, 24 pxor xmm15, xmm8 movdqa xmm8, xmmword ptr [rsp+100H] paddd xmm8, xmm12 paddd xmm9, xmm13 paddd xmm10, xmm14 paddd xmm11, xmm15 pxor xmm4, xmm8 pxor xmm5, xmm9 pxor xmm6, xmm10 pxor xmm7, xmm11 movdqa xmmword ptr [rsp+100H], xmm8 movdqa xmm8, xmm4 psrld xmm8, 7 pslld xmm4, 25 por xmm4, xmm8 movdqa xmm8, xmm5 psrld xmm8, 7 pslld xmm5, 25 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 7 pslld xmm6, 25 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 7 pslld xmm7, 25 por xmm7, xmm8 paddd xmm0, xmmword ptr [rsp+70H] paddd xmm1, xmmword ptr [rsp+50H] paddd xmm2, xmmword ptr [rsp] paddd xmm3, xmmword ptr [rsp+60H] paddd xmm0, xmm5 paddd xmm1, xmm6 paddd xmm2, xmm7 paddd xmm3, xmm4 pxor xmm15, xmm0 pxor xmm12, xmm1 pxor xmm13, xmm2 pxor xmm14, xmm3 pshuflw xmm15, xmm15, 0B1H pshufhw xmm15, xmm15, 0B1H pshuflw xmm12, xmm12, 0B1H pshufhw xmm12, xmm12, 0B1H pshuflw xmm13, xmm13, 0B1H pshufhw xmm13, xmm13, 0B1H pshuflw xmm14, xmm14, 0B1H pshufhw xmm14, xmm14, 0B1H paddd xmm10, xmm15 paddd xmm11, xmm12 movdqa xmm8, xmmword ptr [rsp+100H] paddd xmm8, xmm13 paddd xmm9, xmm14 pxor xmm5, xmm10 pxor xmm6, xmm11 pxor xmm7, xmm8 pxor xmm4, xmm9 movdqa xmmword ptr [rsp+100H], xmm8 movdqa xmm8, xmm5 psrld xmm8, 12 pslld xmm5, 20 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 12 pslld xmm6, 20 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 12 pslld xmm7, 20 por xmm7, xmm8 movdqa xmm8, xmm4 psrld xmm8, 12 pslld xmm4, 20 por xmm4, xmm8 paddd xmm0, xmmword ptr [rsp+20H] paddd xmm1, xmmword ptr [rsp+30H] paddd xmm2, xmmword ptr [rsp+10H] paddd xmm3, xmmword ptr [rsp+40H] paddd xmm0, xmm5 paddd xmm1, xmm6 paddd xmm2, xmm7 paddd xmm3, xmm4 pxor xmm15, xmm0 pxor xmm12, xmm1 pxor xmm13, xmm2 pxor xmm14, xmm3 movdqa xmm8, xmm15 psrld xmm15, 8 pslld xmm8, 24 pxor xmm15, xmm8 movdqa xmm8, xmm12 psrld xmm12, 8 pslld xmm8, 24 pxor xmm12, xmm8 movdqa xmm8, xmm13 psrld xmm13, 8 pslld xmm8, 24 pxor xmm13, xmm8 movdqa xmm8, xmm14 psrld xmm14, 8 pslld xmm8, 24 pxor xmm14, xmm8 paddd xmm10, xmm15 paddd xmm11, xmm12 movdqa xmm8, xmmword ptr [rsp+100H] paddd xmm8, xmm13 paddd xmm9, xmm14 pxor xmm5, xmm10 pxor xmm6, xmm11 pxor xmm7, xmm8 pxor xmm4, xmm9 movdqa xmmword ptr [rsp+100H], xmm8 movdqa xmm8, xmm5 psrld xmm8, 7 pslld xmm5, 25 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 7 pslld xmm6, 25 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 7 pslld xmm7, 25 por xmm7, xmm8 movdqa xmm8, xmm4 psrld xmm8, 7 pslld xmm4, 25 por xmm4, xmm8 paddd xmm0, xmmword ptr [rsp+90H] paddd xmm1, xmmword ptr [rsp+0B0H] paddd xmm2, xmmword ptr [rsp+80H] paddd xmm3, xmmword ptr [rsp+0F0H] paddd xmm0, xmm4 paddd xmm1, xmm5 paddd xmm2, xmm6 paddd xmm3, xmm7 pxor xmm12, xmm0 pxor xmm13, xmm1 pxor xmm14, xmm2 pxor xmm15, xmm3 pshuflw xmm12, xmm12, 0B1H pshufhw xmm12, xmm12, 0B1H pshuflw xmm13, xmm13, 0B1H pshufhw xmm13, xmm13, 0B1H pshuflw xmm14, xmm14, 0B1H pshufhw xmm14, xmm14, 0B1H pshuflw xmm15, xmm15, 0B1H pshufhw xmm15, xmm15, 0B1H movdqa xmm8, xmmword ptr [rsp+100H] paddd xmm8, xmm12 paddd xmm9, xmm13 paddd xmm10, xmm14 paddd xmm11, xmm15 pxor xmm4, xmm8 pxor xmm5, xmm9 pxor xmm6, xmm10 pxor xmm7, xmm11 movdqa xmmword ptr [rsp+100H], xmm8 movdqa xmm8, xmm4 psrld xmm8, 12 pslld xmm4, 20 por xmm4, xmm8 movdqa xmm8, xmm5 psrld xmm8, 12 pslld xmm5, 20 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 12 pslld xmm6, 20 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 12 pslld xmm7, 20 por xmm7, xmm8 paddd xmm0, xmmword ptr [rsp+0E0H] paddd xmm1, xmmword ptr [rsp+50H] paddd xmm2, xmmword ptr [rsp+0C0H] paddd xmm3, xmmword ptr [rsp+10H] paddd xmm0, xmm4 paddd xmm1, xmm5 paddd xmm2, xmm6 paddd xmm3, xmm7 pxor xmm12, xmm0 pxor xmm13, xmm1 pxor xmm14, xmm2 pxor xmm15, xmm3 movdqa xmm8, xmm12 psrld xmm12, 8 pslld xmm8, 24 pxor xmm12, xmm8 movdqa xmm8, xmm13 psrld xmm13, 8 pslld xmm8, 24 pxor xmm13, xmm8 movdqa xmm8, xmm14 psrld xmm14, 8 pslld xmm8, 24 pxor xmm14, xmm8 movdqa xmm8, xmm15 psrld xmm15, 8 pslld xmm8, 24 pxor xmm15, xmm8 movdqa xmm8, xmmword ptr [rsp+100H] paddd xmm8, xmm12 paddd xmm9, xmm13 paddd xmm10, xmm14 paddd xmm11, xmm15 pxor xmm4, xmm8 pxor xmm5, xmm9 pxor xmm6, xmm10 pxor xmm7, xmm11 movdqa xmmword ptr [rsp+100H], xmm8 movdqa xmm8, xmm4 psrld xmm8, 7 pslld xmm4, 25 por xmm4, xmm8 movdqa xmm8, xmm5 psrld xmm8, 7 pslld xmm5, 25 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 7 pslld xmm6, 25 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 7 pslld xmm7, 25 por xmm7, xmm8 paddd xmm0, xmmword ptr [rsp+0D0H] paddd xmm1, xmmword ptr [rsp] paddd xmm2, xmmword ptr [rsp+20H] paddd xmm3, xmmword ptr [rsp+40H] paddd xmm0, xmm5 paddd xmm1, xmm6 paddd xmm2, xmm7 paddd xmm3, xmm4 pxor xmm15, xmm0 pxor xmm12, xmm1 pxor xmm13, xmm2 pxor xmm14, xmm3 pshuflw xmm15, xmm15, 0B1H pshufhw xmm15, xmm15, 0B1H pshuflw xmm12, xmm12, 0B1H pshufhw xmm12, xmm12, 0B1H pshuflw xmm13, xmm13, 0B1H pshufhw xmm13, xmm13, 0B1H pshuflw xmm14, xmm14, 0B1H pshufhw xmm14, xmm14, 0B1H paddd xmm10, xmm15 paddd xmm11, xmm12 movdqa xmm8, xmmword ptr [rsp+100H] paddd xmm8, xmm13 paddd xmm9, xmm14 pxor xmm5, xmm10 pxor xmm6, xmm11 pxor xmm7, xmm8 pxor xmm4, xmm9 movdqa xmmword ptr [rsp+100H], xmm8 movdqa xmm8, xmm5 psrld xmm8, 12 pslld xmm5, 20 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 12 pslld xmm6, 20 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 12 pslld xmm7, 20 por xmm7, xmm8 movdqa xmm8, xmm4 psrld xmm8, 12 pslld xmm4, 20 por xmm4, xmm8 paddd xmm0, xmmword ptr [rsp+30H] paddd xmm1, xmmword ptr [rsp+0A0H] paddd xmm2, xmmword ptr [rsp+60H] paddd xmm3, xmmword ptr [rsp+70H] paddd xmm0, xmm5 paddd xmm1, xmm6 paddd xmm2, xmm7 paddd xmm3, xmm4 pxor xmm15, xmm0 pxor xmm12, xmm1 pxor xmm13, xmm2 pxor xmm14, xmm3 movdqa xmm8, xmm15 psrld xmm15, 8 pslld xmm8, 24 pxor xmm15, xmm8 movdqa xmm8, xmm12 psrld xmm12, 8 pslld xmm8, 24 pxor xmm12, xmm8 movdqa xmm8, xmm13 psrld xmm13, 8 pslld xmm8, 24 pxor xmm13, xmm8 movdqa xmm8, xmm14 psrld xmm14, 8 pslld xmm8, 24 pxor xmm14, xmm8 paddd xmm10, xmm15 paddd xmm11, xmm12 movdqa xmm8, xmmword ptr [rsp+100H] paddd xmm8, xmm13 paddd xmm9, xmm14 pxor xmm5, xmm10 pxor xmm6, xmm11 pxor xmm7, xmm8 pxor xmm4, xmm9 movdqa xmmword ptr [rsp+100H], xmm8 movdqa xmm8, xmm5 psrld xmm8, 7 pslld xmm5, 25 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 7 pslld xmm6, 25 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 7 pslld xmm7, 25 por xmm7, xmm8 movdqa xmm8, xmm4 psrld xmm8, 7 pslld xmm4, 25 por xmm4, xmm8 paddd xmm0, xmmword ptr [rsp+0B0H] paddd xmm1, xmmword ptr [rsp+50H] paddd xmm2, xmmword ptr [rsp+10H] paddd xmm3, xmmword ptr [rsp+80H] paddd xmm0, xmm4 paddd xmm1, xmm5 paddd xmm2, xmm6 paddd xmm3, xmm7 pxor xmm12, xmm0 pxor xmm13, xmm1 pxor xmm14, xmm2 pxor xmm15, xmm3 pshuflw xmm12, xmm12, 0B1H pshufhw xmm12, xmm12, 0B1H pshuflw xmm13, xmm13, 0B1H pshufhw xmm13, xmm13, 0B1H pshuflw xmm14, xmm14, 0B1H pshufhw xmm14, xmm14, 0B1H pshuflw xmm15, xmm15, 0B1H pshufhw xmm15, xmm15, 0B1H movdqa xmm8, xmmword ptr [rsp+100H] paddd xmm8, xmm12 paddd xmm9, xmm13 paddd xmm10, xmm14 paddd xmm11, xmm15 pxor xmm4, xmm8 pxor xmm5, xmm9 pxor xmm6, xmm10 pxor xmm7, xmm11 movdqa xmmword ptr [rsp+100H], xmm8 movdqa xmm8, xmm4 psrld xmm8, 12 pslld xmm4, 20 por xmm4, xmm8 movdqa xmm8, xmm5 psrld xmm8, 12 pslld xmm5, 20 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 12 pslld xmm6, 20 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 12 pslld xmm7, 20 por xmm7, xmm8 paddd xmm0, xmmword ptr [rsp+0F0H] paddd xmm1, xmmword ptr [rsp] paddd xmm2, xmmword ptr [rsp+90H] paddd xmm3, xmmword ptr [rsp+60H] paddd xmm0, xmm4 paddd xmm1, xmm5 paddd xmm2, xmm6 paddd xmm3, xmm7 pxor xmm12, xmm0 pxor xmm13, xmm1 pxor xmm14, xmm2 pxor xmm15, xmm3 movdqa xmm8, xmm12 psrld xmm12, 8 pslld xmm8, 24 pxor xmm12, xmm8 movdqa xmm8, xmm13 psrld xmm13, 8 pslld xmm8, 24 pxor xmm13, xmm8 movdqa xmm8, xmm14 psrld xmm14, 8 pslld xmm8, 24 pxor xmm14, xmm8 movdqa xmm8, xmm15 psrld xmm15, 8 pslld xmm8, 24 pxor xmm15, xmm8 movdqa xmm8, xmmword ptr [rsp+100H] paddd xmm8, xmm12 paddd xmm9, xmm13 paddd xmm10, xmm14 paddd xmm11, xmm15 pxor xmm4, xmm8 pxor xmm5, xmm9 pxor xmm6, xmm10 pxor xmm7, xmm11 movdqa xmmword ptr [rsp+100H], xmm8 movdqa xmm8, xmm4 psrld xmm8, 7 pslld xmm4, 25 por xmm4, xmm8 movdqa xmm8, xmm5 psrld xmm8, 7 pslld xmm5, 25 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 7 pslld xmm6, 25 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 7 pslld xmm7, 25 por xmm7, xmm8 paddd xmm0, xmmword ptr [rsp+0E0H] paddd xmm1, xmmword ptr [rsp+20H] paddd xmm2, xmmword ptr [rsp+30H] paddd xmm3, xmmword ptr [rsp+70H] paddd xmm0, xmm5 paddd xmm1, xmm6 paddd xmm2, xmm7 paddd xmm3, xmm4 pxor xmm15, xmm0 pxor xmm12, xmm1 pxor xmm13, xmm2 pxor xmm14, xmm3 pshuflw xmm15, xmm15, 0B1H pshufhw xmm15, xmm15, 0B1H pshuflw xmm12, xmm12, 0B1H pshufhw xmm12, xmm12, 0B1H pshuflw xmm13, xmm13, 0B1H pshufhw xmm13, xmm13, 0B1H pshuflw xmm14, xmm14, 0B1H pshufhw xmm14, xmm14, 0B1H paddd xmm10, xmm15 paddd xmm11, xmm12 movdqa xmm8, xmmword ptr [rsp+100H] paddd xmm8, xmm13 paddd xmm9, xmm14 pxor xmm5, xmm10 pxor xmm6, xmm11 pxor xmm7, xmm8 pxor xmm4, xmm9 movdqa xmmword ptr [rsp+100H], xmm8 movdqa xmm8, xmm5 psrld xmm8, 12 pslld xmm5, 20 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 12 pslld xmm6, 20 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 12 pslld xmm7, 20 por xmm7, xmm8 movdqa xmm8, xmm4 psrld xmm8, 12 pslld xmm4, 20 por xmm4, xmm8 paddd xmm0, xmmword ptr [rsp+0A0H] paddd xmm1, xmmword ptr [rsp+0C0H] paddd xmm2, xmmword ptr [rsp+40H] paddd xmm3, xmmword ptr [rsp+0D0H] paddd xmm0, xmm5 paddd xmm1, xmm6 paddd xmm2, xmm7 paddd xmm3, xmm4 pxor xmm15, xmm0 pxor xmm12, xmm1 pxor xmm13, xmm2 pxor xmm14, xmm3 movdqa xmm8, xmm15 psrld xmm15, 8 pslld xmm8, 24 pxor xmm15, xmm8 movdqa xmm8, xmm12 psrld xmm12, 8 pslld xmm8, 24 pxor xmm12, xmm8 movdqa xmm8, xmm13 psrld xmm13, 8 pslld xmm8, 24 pxor xmm13, xmm8 movdqa xmm8, xmm14 psrld xmm14, 8 pslld xmm8, 24 pxor xmm14, xmm8 paddd xmm10, xmm15 paddd xmm11, xmm12 movdqa xmm8, xmmword ptr [rsp+100H] paddd xmm8, xmm13 paddd xmm9, xmm14 pxor xmm5, xmm10 pxor xmm6, xmm11 pxor xmm7, xmm8 pxor xmm4, xmm9 pxor xmm0, xmm8 pxor xmm1, xmm9 pxor xmm2, xmm10 pxor xmm3, xmm11 movdqa xmm8, xmm5 psrld xmm8, 7 pslld xmm5, 25 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 7 pslld xmm6, 25 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 7 pslld xmm7, 25 por xmm7, xmm8 movdqa xmm8, xmm4 psrld xmm8, 7 pslld xmm4, 25 por xmm4, xmm8 pxor xmm4, xmm12 pxor xmm5, xmm13 pxor xmm6, xmm14 pxor xmm7, xmm15 mov eax, r13d jne innerloop4 movdqa xmm9, xmm0 punpckldq xmm0, xmm1 punpckhdq xmm9, xmm1 movdqa xmm11, xmm2 punpckldq xmm2, xmm3 punpckhdq xmm11, xmm3 movdqa xmm1, xmm0 punpcklqdq xmm0, xmm2 punpckhqdq xmm1, xmm2 movdqa xmm3, xmm9 punpcklqdq xmm9, xmm11 punpckhqdq xmm3, xmm11 movdqu xmmword ptr [rbx], xmm0 movdqu xmmword ptr [rbx+20H], xmm1 movdqu xmmword ptr [rbx+40H], xmm9 movdqu xmmword ptr [rbx+60H], xmm3 movdqa xmm9, xmm4 punpckldq xmm4, xmm5 punpckhdq xmm9, xmm5 movdqa xmm11, xmm6 punpckldq xmm6, xmm7 punpckhdq xmm11, xmm7 movdqa xmm5, xmm4 punpcklqdq xmm4, xmm6 punpckhqdq xmm5, xmm6 movdqa xmm7, xmm9 punpcklqdq xmm9, xmm11 punpckhqdq xmm7, xmm11 movdqu xmmword ptr [rbx+10H], xmm4 movdqu xmmword ptr [rbx+30H], xmm5 movdqu xmmword ptr [rbx+50H], xmm9 movdqu xmmword ptr [rbx+70H], xmm7 movdqa xmm1, xmmword ptr [rsp+110H] movdqa xmm0, xmm1 paddd xmm1, xmmword ptr [rsp+150H] movdqa xmmword ptr [rsp+110H], xmm1 pxor xmm0, xmmword ptr [CMP_MSB_MASK] pxor xmm1, xmmword ptr [CMP_MSB_MASK] pcmpgtd xmm0, xmm1 movdqa xmm1, xmmword ptr [rsp+120H] psubd xmm1, xmm0 movdqa xmmword ptr [rsp+120H], xmm1 add rbx, 128 add rdi, 32 sub rsi, 4 cmp rsi, 4 jnc outerloop4 test rsi, rsi jne final3blocks unwind: movdqa xmm6, xmmword ptr [rsp+170H] movdqa xmm7, xmmword ptr [rsp+180H] movdqa xmm8, xmmword ptr [rsp+190H] movdqa xmm9, xmmword ptr [rsp+1A0H] movdqa xmm10, xmmword ptr [rsp+1B0H] movdqa xmm11, xmmword ptr [rsp+1C0H] movdqa xmm12, xmmword ptr [rsp+1D0H] movdqa xmm13, xmmword ptr [rsp+1E0H] movdqa xmm14, xmmword ptr [rsp+1F0H] movdqa xmm15, xmmword ptr [rsp+200H] mov rsp, rbp pop rbp pop rbx pop rdi pop rsi pop r12 pop r13 pop r14 pop r15 ret ALIGN 16 final3blocks: test esi, 2H je final1block movups xmm0, xmmword ptr [rcx] movups xmm1, xmmword ptr [rcx+10H] movaps xmm8, xmm0 movaps xmm9, xmm1 movd xmm13, dword ptr [rsp+110H] movd xmm14, dword ptr [rsp+120H] punpckldq xmm13, xmm14 movaps xmmword ptr [rsp], xmm13 movd xmm14, dword ptr [rsp+114H] movd xmm13, dword ptr [rsp+124H] punpckldq xmm14, xmm13 movaps xmmword ptr [rsp+10H], xmm14 mov r8, qword ptr [rdi] mov r9, qword ptr [rdi+8H] movzx eax, byte ptr [rbp+80H] or eax, r13d xor edx, edx innerloop2: mov r14d, eax or eax, r12d add rdx, 64 cmp rdx, r15 cmovne eax, r14d movaps xmm2, xmmword ptr [BLAKE3_IV] movaps xmm10, xmm2 movups xmm4, xmmword ptr [r8+rdx-40H] movups xmm5, xmmword ptr [r8+rdx-30H] movaps xmm3, xmm4 shufps xmm4, xmm5, 136 shufps xmm3, xmm5, 221 movaps xmm5, xmm3 movups xmm6, xmmword ptr [r8+rdx-20H] movups xmm7, xmmword ptr [r8+rdx-10H] movaps xmm3, xmm6 shufps xmm6, xmm7, 136 pshufd xmm6, xmm6, 93H shufps xmm3, xmm7, 221 pshufd xmm7, xmm3, 93H movups xmm12, xmmword ptr [r9+rdx-40H] movups xmm13, xmmword ptr [r9+rdx-30H] movaps xmm11, xmm12 shufps xmm12, xmm13, 136 shufps xmm11, xmm13, 221 movaps xmm13, xmm11 movups xmm14, xmmword ptr [r9+rdx-20H] movups xmm15, xmmword ptr [r9+rdx-10H] movaps xmm11, xmm14 shufps xmm14, xmm15, 136 pshufd xmm14, xmm14, 93H shufps xmm11, xmm15, 221 pshufd xmm15, xmm11, 93H shl rax, 20H or rax, 40H movd xmm3, rax movdqa xmmword ptr [rsp+20H], xmm3 movaps xmm3, xmmword ptr [rsp] movaps xmm11, xmmword ptr [rsp+10H] punpcklqdq xmm3, xmmword ptr [rsp+20H] punpcklqdq xmm11, xmmword ptr [rsp+20H] mov al, 7 roundloop2: paddd xmm0, xmm4 paddd xmm8, xmm12 movaps xmmword ptr [rsp+20H], xmm4 movaps xmmword ptr [rsp+30H], xmm12 paddd xmm0, xmm1 paddd xmm8, xmm9 pxor xmm3, xmm0 pxor xmm11, xmm8 pshuflw xmm3, xmm3, 0B1H pshufhw xmm3, xmm3, 0B1H pshuflw xmm11, xmm11, 0B1H pshufhw xmm11, xmm11, 0B1H paddd xmm2, xmm3 paddd xmm10, xmm11 pxor xmm1, xmm2 pxor xmm9, xmm10 movdqa xmm4, xmm1 pslld xmm1, 20 psrld xmm4, 12 por xmm1, xmm4 movdqa xmm4, xmm9 pslld xmm9, 20 psrld xmm4, 12 por xmm9, xmm4 paddd xmm0, xmm5 paddd xmm8, xmm13 movaps xmmword ptr [rsp+40H], xmm5 movaps xmmword ptr [rsp+50H], xmm13 paddd xmm0, xmm1 paddd xmm8, xmm9 pxor xmm3, xmm0 pxor xmm11, xmm8 movdqa xmm13, xmm3 psrld xmm3, 8 pslld xmm13, 24 pxor xmm3, xmm13 movdqa xmm13, xmm11 psrld xmm11, 8 pslld xmm13, 24 pxor xmm11, xmm13 paddd xmm2, xmm3 paddd xmm10, xmm11 pxor xmm1, xmm2 pxor xmm9, xmm10 movdqa xmm4, xmm1 pslld xmm1, 25 psrld xmm4, 7 por xmm1, xmm4 movdqa xmm4, xmm9 pslld xmm9, 25 psrld xmm4, 7 por xmm9, xmm4 pshufd xmm0, xmm0, 93H pshufd xmm8, xmm8, 93H pshufd xmm3, xmm3, 4EH pshufd xmm11, xmm11, 4EH pshufd xmm2, xmm2, 39H pshufd xmm10, xmm10, 39H paddd xmm0, xmm6 paddd xmm8, xmm14 paddd xmm0, xmm1 paddd xmm8, xmm9 pxor xmm3, xmm0 pxor xmm11, xmm8 pshuflw xmm3, xmm3, 0B1H pshufhw xmm3, xmm3, 0B1H pshuflw xmm11, xmm11, 0B1H pshufhw xmm11, xmm11, 0B1H paddd xmm2, xmm3 paddd xmm10, xmm11 pxor xmm1, xmm2 pxor xmm9, xmm10 movdqa xmm4, xmm1 pslld xmm1, 20 psrld xmm4, 12 por xmm1, xmm4 movdqa xmm4, xmm9 pslld xmm9, 20 psrld xmm4, 12 por xmm9, xmm4 paddd xmm0, xmm7 paddd xmm8, xmm15 paddd xmm0, xmm1 paddd xmm8, xmm9 pxor xmm3, xmm0 pxor xmm11, xmm8 movdqa xmm13, xmm3 psrld xmm3, 8 pslld xmm13, 24 pxor xmm3, xmm13 movdqa xmm13, xmm11 psrld xmm11, 8 pslld xmm13, 24 pxor xmm11, xmm13 paddd xmm2, xmm3 paddd xmm10, xmm11 pxor xmm1, xmm2 pxor xmm9, xmm10 movdqa xmm4, xmm1 pslld xmm1, 25 psrld xmm4, 7 por xmm1, xmm4 movdqa xmm4, xmm9 pslld xmm9, 25 psrld xmm4, 7 por xmm9, xmm4 pshufd xmm0, xmm0, 39H pshufd xmm8, xmm8, 39H pshufd xmm3, xmm3, 4EH pshufd xmm11, xmm11, 4EH pshufd xmm2, xmm2, 93H pshufd xmm10, xmm10, 93H dec al je endroundloop2 movdqa xmm12, xmmword ptr [rsp+20H] movdqa xmm5, xmmword ptr [rsp+40H] pshufd xmm13, xmm12, 0FH shufps xmm12, xmm5, 214 pshufd xmm4, xmm12, 39H movdqa xmm12, xmm6 shufps xmm12, xmm7, 250 pand xmm13, xmmword ptr [PBLENDW_0x33_MASK] pand xmm12, xmmword ptr [PBLENDW_0xCC_MASK] por xmm13, xmm12 movdqa xmmword ptr [rsp+20H], xmm13 movdqa xmm12, xmm7 punpcklqdq xmm12, xmm5 movdqa xmm13, xmm6 pand xmm12, xmmword ptr [PBLENDW_0x3F_MASK] pand xmm13, xmmword ptr [PBLENDW_0xC0_MASK] por xmm12, xmm13 pshufd xmm12, xmm12, 78H punpckhdq xmm5, xmm7 punpckldq xmm6, xmm5 pshufd xmm7, xmm6, 1EH movdqa xmmword ptr [rsp+40H], xmm12 movdqa xmm5, xmmword ptr [rsp+30H] movdqa xmm13, xmmword ptr [rsp+50H] pshufd xmm6, xmm5, 0FH shufps xmm5, xmm13, 214 pshufd xmm12, xmm5, 39H movdqa xmm5, xmm14 shufps xmm5, xmm15, 250 pand xmm6, xmmword ptr [PBLENDW_0x33_MASK] pand xmm5, xmmword ptr [PBLENDW_0xCC_MASK] por xmm6, xmm5 movdqa xmm5, xmm15 punpcklqdq xmm5, xmm13 movdqa xmmword ptr [rsp+30H], xmm2 movdqa xmm2, xmm14 pand xmm5, xmmword ptr [PBLENDW_0x3F_MASK] pand xmm2, xmmword ptr [PBLENDW_0xC0_MASK] por xmm5, xmm2 movdqa xmm2, xmmword ptr [rsp+30H] pshufd xmm5, xmm5, 78H punpckhdq xmm13, xmm15 punpckldq xmm14, xmm13 pshufd xmm15, xmm14, 1EH movdqa xmm13, xmm6 movdqa xmm14, xmm5 movdqa xmm5, xmmword ptr [rsp+20H] movdqa xmm6, xmmword ptr [rsp+40H] jmp roundloop2 endroundloop2: pxor xmm0, xmm2 pxor xmm1, xmm3 pxor xmm8, xmm10 pxor xmm9, xmm11 mov eax, r13d cmp rdx, r15 jne innerloop2 movups xmmword ptr [rbx], xmm0 movups xmmword ptr [rbx+10H], xmm1 movups xmmword ptr [rbx+20H], xmm8 movups xmmword ptr [rbx+30H], xmm9 mov eax, dword ptr [rsp+130H] neg eax mov r10d, dword ptr [rsp+110H+8*rax] mov r11d, dword ptr [rsp+120H+8*rax] mov dword ptr [rsp+110H], r10d mov dword ptr [rsp+120H], r11d add rdi, 16 add rbx, 64 sub rsi, 2 final1block: test esi, 1H je unwind movups xmm0, xmmword ptr [rcx] movups xmm1, xmmword ptr [rcx+10H] movd xmm13, dword ptr [rsp+110H] movd xmm14, dword ptr [rsp+120H] punpckldq xmm13, xmm14 mov r8, qword ptr [rdi] movzx eax, byte ptr [rbp+80H] or eax, r13d xor edx, edx innerloop1: mov r14d, eax or eax, r12d add rdx, 64 cmp rdx, r15 cmovne eax, r14d movaps xmm2, xmmword ptr [BLAKE3_IV] shl rax, 32 or rax, 64 movd xmm12, rax movdqa xmm3, xmm13 punpcklqdq xmm3, xmm12 movups xmm4, xmmword ptr [r8+rdx-40H] movups xmm5, xmmword ptr [r8+rdx-30H] movaps xmm8, xmm4 shufps xmm4, xmm5, 136 shufps xmm8, xmm5, 221 movaps xmm5, xmm8 movups xmm6, xmmword ptr [r8+rdx-20H] movups xmm7, xmmword ptr [r8+rdx-10H] movaps xmm8, xmm6 shufps xmm6, xmm7, 136 pshufd xmm6, xmm6, 93H shufps xmm8, xmm7, 221 pshufd xmm7, xmm8, 93H mov al, 7 roundloop1: paddd xmm0, xmm4 paddd xmm0, xmm1 pxor xmm3, xmm0 pshuflw xmm3, xmm3, 0B1H pshufhw xmm3, xmm3, 0B1H paddd xmm2, xmm3 pxor xmm1, xmm2 movdqa xmm11, xmm1 pslld xmm1, 20 psrld xmm11, 12 por xmm1, xmm11 paddd xmm0, xmm5 paddd xmm0, xmm1 pxor xmm3, xmm0 movdqa xmm14, xmm3 psrld xmm3, 8 pslld xmm14, 24 pxor xmm3, xmm14 paddd xmm2, xmm3 pxor xmm1, xmm2 movdqa xmm11, xmm1 pslld xmm1, 25 psrld xmm11, 7 por xmm1, xmm11 pshufd xmm0, xmm0, 93H pshufd xmm3, xmm3, 4EH pshufd xmm2, xmm2, 39H paddd xmm0, xmm6 paddd xmm0, xmm1 pxor xmm3, xmm0 pshuflw xmm3, xmm3, 0B1H pshufhw xmm3, xmm3, 0B1H paddd xmm2, xmm3 pxor xmm1, xmm2 movdqa xmm11, xmm1 pslld xmm1, 20 psrld xmm11, 12 por xmm1, xmm11 paddd xmm0, xmm7 paddd xmm0, xmm1 pxor xmm3, xmm0 movdqa xmm14, xmm3 psrld xmm3, 8 pslld xmm14, 24 pxor xmm3, xmm14 paddd xmm2, xmm3 pxor xmm1, xmm2 movdqa xmm11, xmm1 pslld xmm1, 25 psrld xmm11, 7 por xmm1, xmm11 pshufd xmm0, xmm0, 39H pshufd xmm3, xmm3, 4EH pshufd xmm2, xmm2, 93H dec al jz endroundloop1 movdqa xmm8, xmm4 shufps xmm8, xmm5, 214 pshufd xmm9, xmm4, 0FH pshufd xmm4, xmm8, 39H movdqa xmm8, xmm6 shufps xmm8, xmm7, 250 pand xmm9, xmmword ptr [PBLENDW_0x33_MASK] pand xmm8, xmmword ptr [PBLENDW_0xCC_MASK] por xmm9, xmm8 movdqa xmm8, xmm7 punpcklqdq xmm8, xmm5 movdqa xmm10, xmm6 pand xmm8, xmmword ptr [PBLENDW_0x3F_MASK] pand xmm10, xmmword ptr [PBLENDW_0xC0_MASK] por xmm8, xmm10 pshufd xmm8, xmm8, 78H punpckhdq xmm5, xmm7 punpckldq xmm6, xmm5 pshufd xmm7, xmm6, 1EH movdqa xmm5, xmm9 movdqa xmm6, xmm8 jmp roundloop1 endroundloop1: pxor xmm0, xmm2 pxor xmm1, xmm3 mov eax, r13d cmp rdx, r15 jne innerloop1 movups xmmword ptr [rbx], xmm0 movups xmmword ptr [rbx+10H], xmm1 jmp unwind _blake3_hash_many_sse2 ENDP blake3_hash_many_sse2 ENDP blake3_compress_in_place_sse2 PROC _blake3_compress_in_place_sse2 PROC sub rsp, 120 movdqa xmmword ptr [rsp], xmm6 movdqa xmmword ptr [rsp+10H], xmm7 movdqa xmmword ptr [rsp+20H], xmm8 movdqa xmmword ptr [rsp+30H], xmm9 movdqa xmmword ptr [rsp+40H], xmm11 movdqa xmmword ptr [rsp+50H], xmm14 movdqa xmmword ptr [rsp+60H], xmm15 movups xmm0, xmmword ptr [rcx] movups xmm1, xmmword ptr [rcx+10H] movaps xmm2, xmmword ptr [BLAKE3_IV] movzx eax, byte ptr [rsp+0A0H] movzx r8d, r8b shl rax, 32 add r8, rax movd xmm3, r9 movd xmm4, r8 punpcklqdq xmm3, xmm4 movups xmm4, xmmword ptr [rdx] movups xmm5, xmmword ptr [rdx+10H] movaps xmm8, xmm4 shufps xmm4, xmm5, 136 shufps xmm8, xmm5, 221 movaps xmm5, xmm8 movups xmm6, xmmword ptr [rdx+20H] movups xmm7, xmmword ptr [rdx+30H] movaps xmm8, xmm6 shufps xmm6, xmm7, 136 pshufd xmm6, xmm6, 93H shufps xmm8, xmm7, 221 pshufd xmm7, xmm8, 93H mov al, 7 @@: paddd xmm0, xmm4 paddd xmm0, xmm1 pxor xmm3, xmm0 pshuflw xmm3, xmm3, 0B1H pshufhw xmm3, xmm3, 0B1H paddd xmm2, xmm3 pxor xmm1, xmm2 movdqa xmm11, xmm1 pslld xmm1, 20 psrld xmm11, 12 por xmm1, xmm11 paddd xmm0, xmm5 paddd xmm0, xmm1 pxor xmm3, xmm0 movdqa xmm14, xmm3 psrld xmm3, 8 pslld xmm14, 24 pxor xmm3, xmm14 paddd xmm2, xmm3 pxor xmm1, xmm2 movdqa xmm11, xmm1 pslld xmm1, 25 psrld xmm11, 7 por xmm1, xmm11 pshufd xmm0, xmm0, 93H pshufd xmm3, xmm3, 4EH pshufd xmm2, xmm2, 39H paddd xmm0, xmm6 paddd xmm0, xmm1 pxor xmm3, xmm0 pshuflw xmm3, xmm3, 0B1H pshufhw xmm3, xmm3, 0B1H paddd xmm2, xmm3 pxor xmm1, xmm2 movdqa xmm11, xmm1 pslld xmm1, 20 psrld xmm11, 12 por xmm1, xmm11 paddd xmm0, xmm7 paddd xmm0, xmm1 pxor xmm3, xmm0 movdqa xmm14, xmm3 psrld xmm3, 8 pslld xmm14, 24 pxor xmm3, xmm14 paddd xmm2, xmm3 pxor xmm1, xmm2 movdqa xmm11, xmm1 pslld xmm1, 25 psrld xmm11, 7 por xmm1, xmm11 pshufd xmm0, xmm0, 39H pshufd xmm3, xmm3, 4EH pshufd xmm2, xmm2, 93H dec al jz @F movdqa xmm8, xmm4 shufps xmm8, xmm5, 214 pshufd xmm9, xmm4, 0FH pshufd xmm4, xmm8, 39H movdqa xmm8, xmm6 shufps xmm8, xmm7, 250 pand xmm9, xmmword ptr [PBLENDW_0x33_MASK] pand xmm8, xmmword ptr [PBLENDW_0xCC_MASK] por xmm9, xmm8 movdqa xmm8, xmm7 punpcklqdq xmm8, xmm5 movdqa xmm14, xmm6 pand xmm8, xmmword ptr [PBLENDW_0x3F_MASK] pand xmm14, xmmword ptr [PBLENDW_0xC0_MASK] por xmm8, xmm14 pshufd xmm8, xmm8, 78H punpckhdq xmm5, xmm7 punpckldq xmm6, xmm5 pshufd xmm7, xmm6, 1EH movdqa xmm5, xmm9 movdqa xmm6, xmm8 jmp @B @@: pxor xmm0, xmm2 pxor xmm1, xmm3 movups xmmword ptr [rcx], xmm0 movups xmmword ptr [rcx+10H], xmm1 movdqa xmm6, xmmword ptr [rsp] movdqa xmm7, xmmword ptr [rsp+10H] movdqa xmm8, xmmword ptr [rsp+20H] movdqa xmm9, xmmword ptr [rsp+30H] movdqa xmm11, xmmword ptr [rsp+40H] movdqa xmm14, xmmword ptr [rsp+50H] movdqa xmm15, xmmword ptr [rsp+60H] add rsp, 120 ret _blake3_compress_in_place_sse2 ENDP blake3_compress_in_place_sse2 ENDP ALIGN 16 blake3_compress_xof_sse2 PROC _blake3_compress_xof_sse2 PROC sub rsp, 120 movdqa xmmword ptr [rsp], xmm6 movdqa xmmword ptr [rsp+10H], xmm7 movdqa xmmword ptr [rsp+20H], xmm8 movdqa xmmword ptr [rsp+30H], xmm9 movdqa xmmword ptr [rsp+40H], xmm11 movdqa xmmword ptr [rsp+50H], xmm14 movdqa xmmword ptr [rsp+60H], xmm15 movups xmm0, xmmword ptr [rcx] movups xmm1, xmmword ptr [rcx+10H] movaps xmm2, xmmword ptr [BLAKE3_IV] movzx eax, byte ptr [rsp+0A0H] movzx r8d, r8b mov r10, qword ptr [rsp+0A8H] shl rax, 32 add r8, rax movd xmm3, r9 movd xmm4, r8 punpcklqdq xmm3, xmm4 movups xmm4, xmmword ptr [rdx] movups xmm5, xmmword ptr [rdx+10H] movaps xmm8, xmm4 shufps xmm4, xmm5, 136 shufps xmm8, xmm5, 221 movaps xmm5, xmm8 movups xmm6, xmmword ptr [rdx+20H] movups xmm7, xmmword ptr [rdx+30H] movaps xmm8, xmm6 shufps xmm6, xmm7, 136 pshufd xmm6, xmm6, 93H shufps xmm8, xmm7, 221 pshufd xmm7, xmm8, 93H mov al, 7 @@: paddd xmm0, xmm4 paddd xmm0, xmm1 pxor xmm3, xmm0 pshuflw xmm3, xmm3, 0B1H pshufhw xmm3, xmm3, 0B1H paddd xmm2, xmm3 pxor xmm1, xmm2 movdqa xmm11, xmm1 pslld xmm1, 20 psrld xmm11, 12 por xmm1, xmm11 paddd xmm0, xmm5 paddd xmm0, xmm1 pxor xmm3, xmm0 movdqa xmm14, xmm3 psrld xmm3, 8 pslld xmm14, 24 pxor xmm3, xmm14 paddd xmm2, xmm3 pxor xmm1, xmm2 movdqa xmm11, xmm1 pslld xmm1, 25 psrld xmm11, 7 por xmm1, xmm11 pshufd xmm0, xmm0, 93H pshufd xmm3, xmm3, 4EH pshufd xmm2, xmm2, 39H paddd xmm0, xmm6 paddd xmm0, xmm1 pxor xmm3, xmm0 pshuflw xmm3, xmm3, 0B1H pshufhw xmm3, xmm3, 0B1H paddd xmm2, xmm3 pxor xmm1, xmm2 movdqa xmm11, xmm1 pslld xmm1, 20 psrld xmm11, 12 por xmm1, xmm11 paddd xmm0, xmm7 paddd xmm0, xmm1 pxor xmm3, xmm0 movdqa xmm14, xmm3 psrld xmm3, 8 pslld xmm14, 24 pxor xmm3, xmm14 paddd xmm2, xmm3 pxor xmm1, xmm2 movdqa xmm11, xmm1 pslld xmm1, 25 psrld xmm11, 7 por xmm1, xmm11 pshufd xmm0, xmm0, 39H pshufd xmm3, xmm3, 4EH pshufd xmm2, xmm2, 93H dec al jz @F movdqa xmm8, xmm4 shufps xmm8, xmm5, 214 pshufd xmm9, xmm4, 0FH pshufd xmm4, xmm8, 39H movdqa xmm8, xmm6 shufps xmm8, xmm7, 250 pand xmm9, xmmword ptr [PBLENDW_0x33_MASK] pand xmm8, xmmword ptr [PBLENDW_0xCC_MASK] por xmm9, xmm8 movdqa xmm8, xmm7 punpcklqdq xmm8, xmm5 movdqa xmm14, xmm6 pand xmm8, xmmword ptr [PBLENDW_0x3F_MASK] pand xmm14, xmmword ptr [PBLENDW_0xC0_MASK] por xmm8, xmm14 pshufd xmm8, xmm8, 78H punpckhdq xmm5, xmm7 punpckldq xmm6, xmm5 pshufd xmm7, xmm6, 1EH movdqa xmm5, xmm9 movdqa xmm6, xmm8 jmp @B @@: movdqu xmm4, xmmword ptr [rcx] movdqu xmm5, xmmword ptr [rcx+10H] pxor xmm0, xmm2 pxor xmm1, xmm3 pxor xmm2, xmm4 pxor xmm3, xmm5 movups xmmword ptr [r10], xmm0 movups xmmword ptr [r10+10H], xmm1 movups xmmword ptr [r10+20H], xmm2 movups xmmword ptr [r10+30H], xmm3 movdqa xmm6, xmmword ptr [rsp] movdqa xmm7, xmmword ptr [rsp+10H] movdqa xmm8, xmmword ptr [rsp+20H] movdqa xmm9, xmmword ptr [rsp+30H] movdqa xmm11, xmmword ptr [rsp+40H] movdqa xmm14, xmmword ptr [rsp+50H] movdqa xmm15, xmmword ptr [rsp+60H] add rsp, 120 ret _blake3_compress_xof_sse2 ENDP blake3_compress_xof_sse2 ENDP _TEXT ENDS _RDATA SEGMENT READONLY PAGE ALIAS(".rdata") 'CONST' ALIGN 64 BLAKE3_IV: dd 6A09E667H, 0BB67AE85H, 3C6EF372H, 0A54FF53AH ADD0: dd 0, 1, 2, 3 ADD1: dd 4 dup (4) BLAKE3_IV_0: dd 4 dup (6A09E667H) BLAKE3_IV_1: dd 4 dup (0BB67AE85H) BLAKE3_IV_2: dd 4 dup (3C6EF372H) BLAKE3_IV_3: dd 4 dup (0A54FF53AH) BLAKE3_BLOCK_LEN: dd 4 dup (64) CMP_MSB_MASK: dd 8 dup(80000000H) PBLENDW_0x33_MASK: dd 0FFFFFFFFH, 000000000H, 0FFFFFFFFH, 000000000H PBLENDW_0xCC_MASK: dd 000000000H, 0FFFFFFFFH, 000000000H, 0FFFFFFFFH PBLENDW_0x3F_MASK: dd 0FFFFFFFFH, 0FFFFFFFFH, 0FFFFFFFFH, 000000000H PBLENDW_0xC0_MASK: dd 000000000H, 000000000H, 000000000H, 0FFFFFFFFH _RDATA ENDS END librecast/libs/blake3/c/blake3_sse41.c000066400000000000000000000505151502456746400177110ustar00rootroot00000000000000#include "blake3_impl.h" #include #define DEGREE 4 #define _mm_shuffle_ps2(a, b, c) \ (_mm_castps_si128( \ _mm_shuffle_ps(_mm_castsi128_ps(a), _mm_castsi128_ps(b), (c)))) INLINE __m128i loadu(const uint8_t src[16]) { return _mm_loadu_si128((const __m128i *)src); } INLINE void storeu(__m128i src, uint8_t dest[16]) { _mm_storeu_si128((__m128i *)dest, src); } INLINE __m128i addv(__m128i a, __m128i b) { return _mm_add_epi32(a, b); } // Note that clang-format doesn't like the name "xor" for some reason. INLINE __m128i xorv(__m128i a, __m128i b) { return _mm_xor_si128(a, b); } INLINE __m128i set1(uint32_t x) { return _mm_set1_epi32((int32_t)x); } INLINE __m128i set4(uint32_t a, uint32_t b, uint32_t c, uint32_t d) { return _mm_setr_epi32((int32_t)a, (int32_t)b, (int32_t)c, (int32_t)d); } INLINE __m128i rot16(__m128i x) { return _mm_shuffle_epi8( x, _mm_set_epi8(13, 12, 15, 14, 9, 8, 11, 10, 5, 4, 7, 6, 1, 0, 3, 2)); } INLINE __m128i rot12(__m128i x) { return xorv(_mm_srli_epi32(x, 12), _mm_slli_epi32(x, 32 - 12)); } INLINE __m128i rot8(__m128i x) { return _mm_shuffle_epi8( x, _mm_set_epi8(12, 15, 14, 13, 8, 11, 10, 9, 4, 7, 6, 5, 0, 3, 2, 1)); } INLINE __m128i rot7(__m128i x) { return xorv(_mm_srli_epi32(x, 7), _mm_slli_epi32(x, 32 - 7)); } INLINE void g1(__m128i *row0, __m128i *row1, __m128i *row2, __m128i *row3, __m128i m) { *row0 = addv(addv(*row0, m), *row1); *row3 = xorv(*row3, *row0); *row3 = rot16(*row3); *row2 = addv(*row2, *row3); *row1 = xorv(*row1, *row2); *row1 = rot12(*row1); } INLINE void g2(__m128i *row0, __m128i *row1, __m128i *row2, __m128i *row3, __m128i m) { *row0 = addv(addv(*row0, m), *row1); *row3 = xorv(*row3, *row0); *row3 = rot8(*row3); *row2 = addv(*row2, *row3); *row1 = xorv(*row1, *row2); *row1 = rot7(*row1); } // Note the optimization here of leaving row1 as the unrotated row, rather than // row0. All the message loads below are adjusted to compensate for this. See // discussion at https://github.com/sneves/blake2-avx2/pull/4 INLINE void diagonalize(__m128i *row0, __m128i *row2, __m128i *row3) { *row0 = _mm_shuffle_epi32(*row0, _MM_SHUFFLE(2, 1, 0, 3)); *row3 = _mm_shuffle_epi32(*row3, _MM_SHUFFLE(1, 0, 3, 2)); *row2 = _mm_shuffle_epi32(*row2, _MM_SHUFFLE(0, 3, 2, 1)); } INLINE void undiagonalize(__m128i *row0, __m128i *row2, __m128i *row3) { *row0 = _mm_shuffle_epi32(*row0, _MM_SHUFFLE(0, 3, 2, 1)); *row3 = _mm_shuffle_epi32(*row3, _MM_SHUFFLE(1, 0, 3, 2)); *row2 = _mm_shuffle_epi32(*row2, _MM_SHUFFLE(2, 1, 0, 3)); } INLINE void compress_pre(__m128i rows[4], const uint32_t cv[8], const uint8_t block[BLAKE3_BLOCK_LEN], uint8_t block_len, uint64_t counter, uint8_t flags) { rows[0] = loadu((uint8_t *)&cv[0]); rows[1] = loadu((uint8_t *)&cv[4]); rows[2] = set4(IV[0], IV[1], IV[2], IV[3]); rows[3] = set4(counter_low(counter), counter_high(counter), (uint32_t)block_len, (uint32_t)flags); __m128i m0 = loadu(&block[sizeof(__m128i) * 0]); __m128i m1 = loadu(&block[sizeof(__m128i) * 1]); __m128i m2 = loadu(&block[sizeof(__m128i) * 2]); __m128i m3 = loadu(&block[sizeof(__m128i) * 3]); __m128i t0, t1, t2, t3, tt; // Round 1. The first round permutes the message words from the original // input order, into the groups that get mixed in parallel. t0 = _mm_shuffle_ps2(m0, m1, _MM_SHUFFLE(2, 0, 2, 0)); // 6 4 2 0 g1(&rows[0], &rows[1], &rows[2], &rows[3], t0); t1 = _mm_shuffle_ps2(m0, m1, _MM_SHUFFLE(3, 1, 3, 1)); // 7 5 3 1 g2(&rows[0], &rows[1], &rows[2], &rows[3], t1); diagonalize(&rows[0], &rows[2], &rows[3]); t2 = _mm_shuffle_ps2(m2, m3, _MM_SHUFFLE(2, 0, 2, 0)); // 14 12 10 8 t2 = _mm_shuffle_epi32(t2, _MM_SHUFFLE(2, 1, 0, 3)); // 12 10 8 14 g1(&rows[0], &rows[1], &rows[2], &rows[3], t2); t3 = _mm_shuffle_ps2(m2, m3, _MM_SHUFFLE(3, 1, 3, 1)); // 15 13 11 9 t3 = _mm_shuffle_epi32(t3, _MM_SHUFFLE(2, 1, 0, 3)); // 13 11 9 15 g2(&rows[0], &rows[1], &rows[2], &rows[3], t3); undiagonalize(&rows[0], &rows[2], &rows[3]); m0 = t0; m1 = t1; m2 = t2; m3 = t3; // Round 2. This round and all following rounds apply a fixed permutation // to the message words from the round before. t0 = _mm_shuffle_ps2(m0, m1, _MM_SHUFFLE(3, 1, 1, 2)); t0 = _mm_shuffle_epi32(t0, _MM_SHUFFLE(0, 3, 2, 1)); g1(&rows[0], &rows[1], &rows[2], &rows[3], t0); t1 = _mm_shuffle_ps2(m2, m3, _MM_SHUFFLE(3, 3, 2, 2)); tt = _mm_shuffle_epi32(m0, _MM_SHUFFLE(0, 0, 3, 3)); t1 = _mm_blend_epi16(tt, t1, 0xCC); g2(&rows[0], &rows[1], &rows[2], &rows[3], t1); diagonalize(&rows[0], &rows[2], &rows[3]); t2 = _mm_unpacklo_epi64(m3, m1); tt = _mm_blend_epi16(t2, m2, 0xC0); t2 = _mm_shuffle_epi32(tt, _MM_SHUFFLE(1, 3, 2, 0)); g1(&rows[0], &rows[1], &rows[2], &rows[3], t2); t3 = _mm_unpackhi_epi32(m1, m3); tt = _mm_unpacklo_epi32(m2, t3); t3 = _mm_shuffle_epi32(tt, _MM_SHUFFLE(0, 1, 3, 2)); g2(&rows[0], &rows[1], &rows[2], &rows[3], t3); undiagonalize(&rows[0], &rows[2], &rows[3]); m0 = t0; m1 = t1; m2 = t2; m3 = t3; // Round 3 t0 = _mm_shuffle_ps2(m0, m1, _MM_SHUFFLE(3, 1, 1, 2)); t0 = _mm_shuffle_epi32(t0, _MM_SHUFFLE(0, 3, 2, 1)); g1(&rows[0], &rows[1], &rows[2], &rows[3], t0); t1 = _mm_shuffle_ps2(m2, m3, _MM_SHUFFLE(3, 3, 2, 2)); tt = _mm_shuffle_epi32(m0, _MM_SHUFFLE(0, 0, 3, 3)); t1 = _mm_blend_epi16(tt, t1, 0xCC); g2(&rows[0], &rows[1], &rows[2], &rows[3], t1); diagonalize(&rows[0], &rows[2], &rows[3]); t2 = _mm_unpacklo_epi64(m3, m1); tt = _mm_blend_epi16(t2, m2, 0xC0); t2 = _mm_shuffle_epi32(tt, _MM_SHUFFLE(1, 3, 2, 0)); g1(&rows[0], &rows[1], &rows[2], &rows[3], t2); t3 = _mm_unpackhi_epi32(m1, m3); tt = _mm_unpacklo_epi32(m2, t3); t3 = _mm_shuffle_epi32(tt, _MM_SHUFFLE(0, 1, 3, 2)); g2(&rows[0], &rows[1], &rows[2], &rows[3], t3); undiagonalize(&rows[0], &rows[2], &rows[3]); m0 = t0; m1 = t1; m2 = t2; m3 = t3; // Round 4 t0 = _mm_shuffle_ps2(m0, m1, _MM_SHUFFLE(3, 1, 1, 2)); t0 = _mm_shuffle_epi32(t0, _MM_SHUFFLE(0, 3, 2, 1)); g1(&rows[0], &rows[1], &rows[2], &rows[3], t0); t1 = _mm_shuffle_ps2(m2, m3, _MM_SHUFFLE(3, 3, 2, 2)); tt = _mm_shuffle_epi32(m0, _MM_SHUFFLE(0, 0, 3, 3)); t1 = _mm_blend_epi16(tt, t1, 0xCC); g2(&rows[0], &rows[1], &rows[2], &rows[3], t1); diagonalize(&rows[0], &rows[2], &rows[3]); t2 = _mm_unpacklo_epi64(m3, m1); tt = _mm_blend_epi16(t2, m2, 0xC0); t2 = _mm_shuffle_epi32(tt, _MM_SHUFFLE(1, 3, 2, 0)); g1(&rows[0], &rows[1], &rows[2], &rows[3], t2); t3 = _mm_unpackhi_epi32(m1, m3); tt = _mm_unpacklo_epi32(m2, t3); t3 = _mm_shuffle_epi32(tt, _MM_SHUFFLE(0, 1, 3, 2)); g2(&rows[0], &rows[1], &rows[2], &rows[3], t3); undiagonalize(&rows[0], &rows[2], &rows[3]); m0 = t0; m1 = t1; m2 = t2; m3 = t3; // Round 5 t0 = _mm_shuffle_ps2(m0, m1, _MM_SHUFFLE(3, 1, 1, 2)); t0 = _mm_shuffle_epi32(t0, _MM_SHUFFLE(0, 3, 2, 1)); g1(&rows[0], &rows[1], &rows[2], &rows[3], t0); t1 = _mm_shuffle_ps2(m2, m3, _MM_SHUFFLE(3, 3, 2, 2)); tt = _mm_shuffle_epi32(m0, _MM_SHUFFLE(0, 0, 3, 3)); t1 = _mm_blend_epi16(tt, t1, 0xCC); g2(&rows[0], &rows[1], &rows[2], &rows[3], t1); diagonalize(&rows[0], &rows[2], &rows[3]); t2 = _mm_unpacklo_epi64(m3, m1); tt = _mm_blend_epi16(t2, m2, 0xC0); t2 = _mm_shuffle_epi32(tt, _MM_SHUFFLE(1, 3, 2, 0)); g1(&rows[0], &rows[1], &rows[2], &rows[3], t2); t3 = _mm_unpackhi_epi32(m1, m3); tt = _mm_unpacklo_epi32(m2, t3); t3 = _mm_shuffle_epi32(tt, _MM_SHUFFLE(0, 1, 3, 2)); g2(&rows[0], &rows[1], &rows[2], &rows[3], t3); undiagonalize(&rows[0], &rows[2], &rows[3]); m0 = t0; m1 = t1; m2 = t2; m3 = t3; // Round 6 t0 = _mm_shuffle_ps2(m0, m1, _MM_SHUFFLE(3, 1, 1, 2)); t0 = _mm_shuffle_epi32(t0, _MM_SHUFFLE(0, 3, 2, 1)); g1(&rows[0], &rows[1], &rows[2], &rows[3], t0); t1 = _mm_shuffle_ps2(m2, m3, _MM_SHUFFLE(3, 3, 2, 2)); tt = _mm_shuffle_epi32(m0, _MM_SHUFFLE(0, 0, 3, 3)); t1 = _mm_blend_epi16(tt, t1, 0xCC); g2(&rows[0], &rows[1], &rows[2], &rows[3], t1); diagonalize(&rows[0], &rows[2], &rows[3]); t2 = _mm_unpacklo_epi64(m3, m1); tt = _mm_blend_epi16(t2, m2, 0xC0); t2 = _mm_shuffle_epi32(tt, _MM_SHUFFLE(1, 3, 2, 0)); g1(&rows[0], &rows[1], &rows[2], &rows[3], t2); t3 = _mm_unpackhi_epi32(m1, m3); tt = _mm_unpacklo_epi32(m2, t3); t3 = _mm_shuffle_epi32(tt, _MM_SHUFFLE(0, 1, 3, 2)); g2(&rows[0], &rows[1], &rows[2], &rows[3], t3); undiagonalize(&rows[0], &rows[2], &rows[3]); m0 = t0; m1 = t1; m2 = t2; m3 = t3; // Round 7 t0 = _mm_shuffle_ps2(m0, m1, _MM_SHUFFLE(3, 1, 1, 2)); t0 = _mm_shuffle_epi32(t0, _MM_SHUFFLE(0, 3, 2, 1)); g1(&rows[0], &rows[1], &rows[2], &rows[3], t0); t1 = _mm_shuffle_ps2(m2, m3, _MM_SHUFFLE(3, 3, 2, 2)); tt = _mm_shuffle_epi32(m0, _MM_SHUFFLE(0, 0, 3, 3)); t1 = _mm_blend_epi16(tt, t1, 0xCC); g2(&rows[0], &rows[1], &rows[2], &rows[3], t1); diagonalize(&rows[0], &rows[2], &rows[3]); t2 = _mm_unpacklo_epi64(m3, m1); tt = _mm_blend_epi16(t2, m2, 0xC0); t2 = _mm_shuffle_epi32(tt, _MM_SHUFFLE(1, 3, 2, 0)); g1(&rows[0], &rows[1], &rows[2], &rows[3], t2); t3 = _mm_unpackhi_epi32(m1, m3); tt = _mm_unpacklo_epi32(m2, t3); t3 = _mm_shuffle_epi32(tt, _MM_SHUFFLE(0, 1, 3, 2)); g2(&rows[0], &rows[1], &rows[2], &rows[3], t3); undiagonalize(&rows[0], &rows[2], &rows[3]); } void blake3_compress_in_place_sse41(uint32_t cv[8], const uint8_t block[BLAKE3_BLOCK_LEN], uint8_t block_len, uint64_t counter, uint8_t flags) { __m128i rows[4]; compress_pre(rows, cv, block, block_len, counter, flags); storeu(xorv(rows[0], rows[2]), (uint8_t *)&cv[0]); storeu(xorv(rows[1], rows[3]), (uint8_t *)&cv[4]); } void blake3_compress_xof_sse41(const uint32_t cv[8], const uint8_t block[BLAKE3_BLOCK_LEN], uint8_t block_len, uint64_t counter, uint8_t flags, uint8_t out[64]) { __m128i rows[4]; compress_pre(rows, cv, block, block_len, counter, flags); storeu(xorv(rows[0], rows[2]), &out[0]); storeu(xorv(rows[1], rows[3]), &out[16]); storeu(xorv(rows[2], loadu((uint8_t *)&cv[0])), &out[32]); storeu(xorv(rows[3], loadu((uint8_t *)&cv[4])), &out[48]); } INLINE void round_fn(__m128i v[16], __m128i m[16], size_t r) { v[0] = addv(v[0], m[(size_t)MSG_SCHEDULE[r][0]]); v[1] = addv(v[1], m[(size_t)MSG_SCHEDULE[r][2]]); v[2] = addv(v[2], m[(size_t)MSG_SCHEDULE[r][4]]); v[3] = addv(v[3], m[(size_t)MSG_SCHEDULE[r][6]]); v[0] = addv(v[0], v[4]); v[1] = addv(v[1], v[5]); v[2] = addv(v[2], v[6]); v[3] = addv(v[3], v[7]); v[12] = xorv(v[12], v[0]); v[13] = xorv(v[13], v[1]); v[14] = xorv(v[14], v[2]); v[15] = xorv(v[15], v[3]); v[12] = rot16(v[12]); v[13] = rot16(v[13]); v[14] = rot16(v[14]); v[15] = rot16(v[15]); v[8] = addv(v[8], v[12]); v[9] = addv(v[9], v[13]); v[10] = addv(v[10], v[14]); v[11] = addv(v[11], v[15]); v[4] = xorv(v[4], v[8]); v[5] = xorv(v[5], v[9]); v[6] = xorv(v[6], v[10]); v[7] = xorv(v[7], v[11]); v[4] = rot12(v[4]); v[5] = rot12(v[5]); v[6] = rot12(v[6]); v[7] = rot12(v[7]); v[0] = addv(v[0], m[(size_t)MSG_SCHEDULE[r][1]]); v[1] = addv(v[1], m[(size_t)MSG_SCHEDULE[r][3]]); v[2] = addv(v[2], m[(size_t)MSG_SCHEDULE[r][5]]); v[3] = addv(v[3], m[(size_t)MSG_SCHEDULE[r][7]]); v[0] = addv(v[0], v[4]); v[1] = addv(v[1], v[5]); v[2] = addv(v[2], v[6]); v[3] = addv(v[3], v[7]); v[12] = xorv(v[12], v[0]); v[13] = xorv(v[13], v[1]); v[14] = xorv(v[14], v[2]); v[15] = xorv(v[15], v[3]); v[12] = rot8(v[12]); v[13] = rot8(v[13]); v[14] = rot8(v[14]); v[15] = rot8(v[15]); v[8] = addv(v[8], v[12]); v[9] = addv(v[9], v[13]); v[10] = addv(v[10], v[14]); v[11] = addv(v[11], v[15]); v[4] = xorv(v[4], v[8]); v[5] = xorv(v[5], v[9]); v[6] = xorv(v[6], v[10]); v[7] = xorv(v[7], v[11]); v[4] = rot7(v[4]); v[5] = rot7(v[5]); v[6] = rot7(v[6]); v[7] = rot7(v[7]); v[0] = addv(v[0], m[(size_t)MSG_SCHEDULE[r][8]]); v[1] = addv(v[1], m[(size_t)MSG_SCHEDULE[r][10]]); v[2] = addv(v[2], m[(size_t)MSG_SCHEDULE[r][12]]); v[3] = addv(v[3], m[(size_t)MSG_SCHEDULE[r][14]]); v[0] = addv(v[0], v[5]); v[1] = addv(v[1], v[6]); v[2] = addv(v[2], v[7]); v[3] = addv(v[3], v[4]); v[15] = xorv(v[15], v[0]); v[12] = xorv(v[12], v[1]); v[13] = xorv(v[13], v[2]); v[14] = xorv(v[14], v[3]); v[15] = rot16(v[15]); v[12] = rot16(v[12]); v[13] = rot16(v[13]); v[14] = rot16(v[14]); v[10] = addv(v[10], v[15]); v[11] = addv(v[11], v[12]); v[8] = addv(v[8], v[13]); v[9] = addv(v[9], v[14]); v[5] = xorv(v[5], v[10]); v[6] = xorv(v[6], v[11]); v[7] = xorv(v[7], v[8]); v[4] = xorv(v[4], v[9]); v[5] = rot12(v[5]); v[6] = rot12(v[6]); v[7] = rot12(v[7]); v[4] = rot12(v[4]); v[0] = addv(v[0], m[(size_t)MSG_SCHEDULE[r][9]]); v[1] = addv(v[1], m[(size_t)MSG_SCHEDULE[r][11]]); v[2] = addv(v[2], m[(size_t)MSG_SCHEDULE[r][13]]); v[3] = addv(v[3], m[(size_t)MSG_SCHEDULE[r][15]]); v[0] = addv(v[0], v[5]); v[1] = addv(v[1], v[6]); v[2] = addv(v[2], v[7]); v[3] = addv(v[3], v[4]); v[15] = xorv(v[15], v[0]); v[12] = xorv(v[12], v[1]); v[13] = xorv(v[13], v[2]); v[14] = xorv(v[14], v[3]); v[15] = rot8(v[15]); v[12] = rot8(v[12]); v[13] = rot8(v[13]); v[14] = rot8(v[14]); v[10] = addv(v[10], v[15]); v[11] = addv(v[11], v[12]); v[8] = addv(v[8], v[13]); v[9] = addv(v[9], v[14]); v[5] = xorv(v[5], v[10]); v[6] = xorv(v[6], v[11]); v[7] = xorv(v[7], v[8]); v[4] = xorv(v[4], v[9]); v[5] = rot7(v[5]); v[6] = rot7(v[6]); v[7] = rot7(v[7]); v[4] = rot7(v[4]); } INLINE void transpose_vecs(__m128i vecs[DEGREE]) { // Interleave 32-bit lanes. The low unpack is lanes 00/11 and the high is // 22/33. Note that this doesn't split the vector into two lanes, as the // AVX2 counterparts do. __m128i ab_01 = _mm_unpacklo_epi32(vecs[0], vecs[1]); __m128i ab_23 = _mm_unpackhi_epi32(vecs[0], vecs[1]); __m128i cd_01 = _mm_unpacklo_epi32(vecs[2], vecs[3]); __m128i cd_23 = _mm_unpackhi_epi32(vecs[2], vecs[3]); // Interleave 64-bit lanes. __m128i abcd_0 = _mm_unpacklo_epi64(ab_01, cd_01); __m128i abcd_1 = _mm_unpackhi_epi64(ab_01, cd_01); __m128i abcd_2 = _mm_unpacklo_epi64(ab_23, cd_23); __m128i abcd_3 = _mm_unpackhi_epi64(ab_23, cd_23); vecs[0] = abcd_0; vecs[1] = abcd_1; vecs[2] = abcd_2; vecs[3] = abcd_3; } INLINE void transpose_msg_vecs(const uint8_t *const *inputs, size_t block_offset, __m128i out[16]) { out[0] = loadu(&inputs[0][block_offset + 0 * sizeof(__m128i)]); out[1] = loadu(&inputs[1][block_offset + 0 * sizeof(__m128i)]); out[2] = loadu(&inputs[2][block_offset + 0 * sizeof(__m128i)]); out[3] = loadu(&inputs[3][block_offset + 0 * sizeof(__m128i)]); out[4] = loadu(&inputs[0][block_offset + 1 * sizeof(__m128i)]); out[5] = loadu(&inputs[1][block_offset + 1 * sizeof(__m128i)]); out[6] = loadu(&inputs[2][block_offset + 1 * sizeof(__m128i)]); out[7] = loadu(&inputs[3][block_offset + 1 * sizeof(__m128i)]); out[8] = loadu(&inputs[0][block_offset + 2 * sizeof(__m128i)]); out[9] = loadu(&inputs[1][block_offset + 2 * sizeof(__m128i)]); out[10] = loadu(&inputs[2][block_offset + 2 * sizeof(__m128i)]); out[11] = loadu(&inputs[3][block_offset + 2 * sizeof(__m128i)]); out[12] = loadu(&inputs[0][block_offset + 3 * sizeof(__m128i)]); out[13] = loadu(&inputs[1][block_offset + 3 * sizeof(__m128i)]); out[14] = loadu(&inputs[2][block_offset + 3 * sizeof(__m128i)]); out[15] = loadu(&inputs[3][block_offset + 3 * sizeof(__m128i)]); for (size_t i = 0; i < 4; ++i) { _mm_prefetch((const void *)&inputs[i][block_offset + 256], _MM_HINT_T0); } transpose_vecs(&out[0]); transpose_vecs(&out[4]); transpose_vecs(&out[8]); transpose_vecs(&out[12]); } INLINE void load_counters(uint64_t counter, bool increment_counter, __m128i *out_lo, __m128i *out_hi) { const __m128i mask = _mm_set1_epi32(-(int32_t)increment_counter); const __m128i add0 = _mm_set_epi32(3, 2, 1, 0); const __m128i add1 = _mm_and_si128(mask, add0); __m128i l = _mm_add_epi32(_mm_set1_epi32((int32_t)counter), add1); __m128i carry = _mm_cmpgt_epi32(_mm_xor_si128(add1, _mm_set1_epi32(0x80000000)), _mm_xor_si128( l, _mm_set1_epi32(0x80000000))); __m128i h = _mm_sub_epi32(_mm_set1_epi32((int32_t)(counter >> 32)), carry); *out_lo = l; *out_hi = h; } static void blake3_hash4_sse41(const uint8_t *const *inputs, size_t blocks, const uint32_t key[8], uint64_t counter, bool increment_counter, uint8_t flags, uint8_t flags_start, uint8_t flags_end, uint8_t *out) { __m128i h_vecs[8] = { set1(key[0]), set1(key[1]), set1(key[2]), set1(key[3]), set1(key[4]), set1(key[5]), set1(key[6]), set1(key[7]), }; __m128i counter_low_vec, counter_high_vec; load_counters(counter, increment_counter, &counter_low_vec, &counter_high_vec); uint8_t block_flags = flags | flags_start; for (size_t block = 0; block < blocks; block++) { if (block + 1 == blocks) { block_flags |= flags_end; } __m128i block_len_vec = set1(BLAKE3_BLOCK_LEN); __m128i block_flags_vec = set1(block_flags); __m128i msg_vecs[16]; transpose_msg_vecs(inputs, block * BLAKE3_BLOCK_LEN, msg_vecs); __m128i v[16] = { h_vecs[0], h_vecs[1], h_vecs[2], h_vecs[3], h_vecs[4], h_vecs[5], h_vecs[6], h_vecs[7], set1(IV[0]), set1(IV[1]), set1(IV[2]), set1(IV[3]), counter_low_vec, counter_high_vec, block_len_vec, block_flags_vec, }; round_fn(v, msg_vecs, 0); round_fn(v, msg_vecs, 1); round_fn(v, msg_vecs, 2); round_fn(v, msg_vecs, 3); round_fn(v, msg_vecs, 4); round_fn(v, msg_vecs, 5); round_fn(v, msg_vecs, 6); h_vecs[0] = xorv(v[0], v[8]); h_vecs[1] = xorv(v[1], v[9]); h_vecs[2] = xorv(v[2], v[10]); h_vecs[3] = xorv(v[3], v[11]); h_vecs[4] = xorv(v[4], v[12]); h_vecs[5] = xorv(v[5], v[13]); h_vecs[6] = xorv(v[6], v[14]); h_vecs[7] = xorv(v[7], v[15]); block_flags = flags; } transpose_vecs(&h_vecs[0]); transpose_vecs(&h_vecs[4]); // The first four vecs now contain the first half of each output, and the // second four vecs contain the second half of each output. storeu(h_vecs[0], &out[0 * sizeof(__m128i)]); storeu(h_vecs[4], &out[1 * sizeof(__m128i)]); storeu(h_vecs[1], &out[2 * sizeof(__m128i)]); storeu(h_vecs[5], &out[3 * sizeof(__m128i)]); storeu(h_vecs[2], &out[4 * sizeof(__m128i)]); storeu(h_vecs[6], &out[5 * sizeof(__m128i)]); storeu(h_vecs[3], &out[6 * sizeof(__m128i)]); storeu(h_vecs[7], &out[7 * sizeof(__m128i)]); } INLINE void hash_one_sse41(const uint8_t *input, size_t blocks, const uint32_t key[8], uint64_t counter, uint8_t flags, uint8_t flags_start, uint8_t flags_end, uint8_t out[BLAKE3_OUT_LEN]) { uint32_t cv[8]; memcpy(cv, key, BLAKE3_KEY_LEN); uint8_t block_flags = flags | flags_start; while (blocks > 0) { if (blocks == 1) { block_flags |= flags_end; } blake3_compress_in_place_sse41(cv, input, BLAKE3_BLOCK_LEN, counter, block_flags); input = &input[BLAKE3_BLOCK_LEN]; blocks -= 1; block_flags = flags; } memcpy(out, cv, BLAKE3_OUT_LEN); } void blake3_hash_many_sse41(const uint8_t *const *inputs, size_t num_inputs, size_t blocks, const uint32_t key[8], uint64_t counter, bool increment_counter, uint8_t flags, uint8_t flags_start, uint8_t flags_end, uint8_t *out) { while (num_inputs >= DEGREE) { blake3_hash4_sse41(inputs, blocks, key, counter, increment_counter, flags, flags_start, flags_end, out); if (increment_counter) { counter += DEGREE; } inputs += DEGREE; num_inputs -= DEGREE; out = &out[DEGREE * BLAKE3_OUT_LEN]; } while (num_inputs > 0) { hash_one_sse41(inputs[0], blocks, key, counter, flags, flags_start, flags_end, out); if (increment_counter) { counter += 1; } inputs += 1; num_inputs -= 1; out = &out[BLAKE3_OUT_LEN]; } } librecast/libs/blake3/c/blake3_sse41_x86-64_unix.S000066400000000000000000001673271502456746400217020ustar00rootroot00000000000000#if defined(__ELF__) && defined(__linux__) .section .note.GNU-stack,"",%progbits #endif #if defined(__ELF__) && defined(__CET__) && defined(__has_include) #if __has_include() #include #endif #endif #if !defined(_CET_ENDBR) #define _CET_ENDBR #endif .intel_syntax noprefix .global blake3_hash_many_sse41 .global _blake3_hash_many_sse41 .global blake3_compress_in_place_sse41 .global _blake3_compress_in_place_sse41 .global blake3_compress_xof_sse41 .global _blake3_compress_xof_sse41 #ifdef __APPLE__ .text #else .section .text #endif .p2align 6 _blake3_hash_many_sse41: blake3_hash_many_sse41: _CET_ENDBR push r15 push r14 push r13 push r12 push rbx push rbp mov rbp, rsp sub rsp, 360 and rsp, 0xFFFFFFFFFFFFFFC0 neg r9d movd xmm0, r9d pshufd xmm0, xmm0, 0x00 movdqa xmmword ptr [rsp+0x130], xmm0 movdqa xmm1, xmm0 pand xmm1, xmmword ptr [ADD0+rip] pand xmm0, xmmword ptr [ADD1+rip] movdqa xmmword ptr [rsp+0x150], xmm0 movd xmm0, r8d pshufd xmm0, xmm0, 0x00 paddd xmm0, xmm1 movdqa xmmword ptr [rsp+0x110], xmm0 pxor xmm0, xmmword ptr [CMP_MSB_MASK+rip] pxor xmm1, xmmword ptr [CMP_MSB_MASK+rip] pcmpgtd xmm1, xmm0 shr r8, 32 movd xmm2, r8d pshufd xmm2, xmm2, 0x00 psubd xmm2, xmm1 movdqa xmmword ptr [rsp+0x120], xmm2 mov rbx, qword ptr [rbp+0x50] mov r15, rdx shl r15, 6 movzx r13d, byte ptr [rbp+0x38] movzx r12d, byte ptr [rbp+0x48] cmp rsi, 4 jc 3f 2: movdqu xmm3, xmmword ptr [rcx] pshufd xmm0, xmm3, 0x00 pshufd xmm1, xmm3, 0x55 pshufd xmm2, xmm3, 0xAA pshufd xmm3, xmm3, 0xFF movdqu xmm7, xmmword ptr [rcx+0x10] pshufd xmm4, xmm7, 0x00 pshufd xmm5, xmm7, 0x55 pshufd xmm6, xmm7, 0xAA pshufd xmm7, xmm7, 0xFF mov r8, qword ptr [rdi] mov r9, qword ptr [rdi+0x8] mov r10, qword ptr [rdi+0x10] mov r11, qword ptr [rdi+0x18] movzx eax, byte ptr [rbp+0x40] or eax, r13d xor edx, edx 9: mov r14d, eax or eax, r12d add rdx, 64 cmp rdx, r15 cmovne eax, r14d movdqu xmm8, xmmword ptr [r8+rdx-0x40] movdqu xmm9, xmmword ptr [r9+rdx-0x40] movdqu xmm10, xmmword ptr [r10+rdx-0x40] movdqu xmm11, xmmword ptr [r11+rdx-0x40] movdqa xmm12, xmm8 punpckldq xmm8, xmm9 punpckhdq xmm12, xmm9 movdqa xmm14, xmm10 punpckldq xmm10, xmm11 punpckhdq xmm14, xmm11 movdqa xmm9, xmm8 punpcklqdq xmm8, xmm10 punpckhqdq xmm9, xmm10 movdqa xmm13, xmm12 punpcklqdq xmm12, xmm14 punpckhqdq xmm13, xmm14 movdqa xmmword ptr [rsp], xmm8 movdqa xmmword ptr [rsp+0x10], xmm9 movdqa xmmword ptr [rsp+0x20], xmm12 movdqa xmmword ptr [rsp+0x30], xmm13 movdqu xmm8, xmmword ptr [r8+rdx-0x30] movdqu xmm9, xmmword ptr [r9+rdx-0x30] movdqu xmm10, xmmword ptr [r10+rdx-0x30] movdqu xmm11, xmmword ptr [r11+rdx-0x30] movdqa xmm12, xmm8 punpckldq xmm8, xmm9 punpckhdq xmm12, xmm9 movdqa xmm14, xmm10 punpckldq xmm10, xmm11 punpckhdq xmm14, xmm11 movdqa xmm9, xmm8 punpcklqdq xmm8, xmm10 punpckhqdq xmm9, xmm10 movdqa xmm13, xmm12 punpcklqdq xmm12, xmm14 punpckhqdq xmm13, xmm14 movdqa xmmword ptr [rsp+0x40], xmm8 movdqa xmmword ptr [rsp+0x50], xmm9 movdqa xmmword ptr [rsp+0x60], xmm12 movdqa xmmword ptr [rsp+0x70], xmm13 movdqu xmm8, xmmword ptr [r8+rdx-0x20] movdqu xmm9, xmmword ptr [r9+rdx-0x20] movdqu xmm10, xmmword ptr [r10+rdx-0x20] movdqu xmm11, xmmword ptr [r11+rdx-0x20] movdqa xmm12, xmm8 punpckldq xmm8, xmm9 punpckhdq xmm12, xmm9 movdqa xmm14, xmm10 punpckldq xmm10, xmm11 punpckhdq xmm14, xmm11 movdqa xmm9, xmm8 punpcklqdq xmm8, xmm10 punpckhqdq xmm9, xmm10 movdqa xmm13, xmm12 punpcklqdq xmm12, xmm14 punpckhqdq xmm13, xmm14 movdqa xmmword ptr [rsp+0x80], xmm8 movdqa xmmword ptr [rsp+0x90], xmm9 movdqa xmmword ptr [rsp+0xA0], xmm12 movdqa xmmword ptr [rsp+0xB0], xmm13 movdqu xmm8, xmmword ptr [r8+rdx-0x10] movdqu xmm9, xmmword ptr [r9+rdx-0x10] movdqu xmm10, xmmword ptr [r10+rdx-0x10] movdqu xmm11, xmmword ptr [r11+rdx-0x10] movdqa xmm12, xmm8 punpckldq xmm8, xmm9 punpckhdq xmm12, xmm9 movdqa xmm14, xmm10 punpckldq xmm10, xmm11 punpckhdq xmm14, xmm11 movdqa xmm9, xmm8 punpcklqdq xmm8, xmm10 punpckhqdq xmm9, xmm10 movdqa xmm13, xmm12 punpcklqdq xmm12, xmm14 punpckhqdq xmm13, xmm14 movdqa xmmword ptr [rsp+0xC0], xmm8 movdqa xmmword ptr [rsp+0xD0], xmm9 movdqa xmmword ptr [rsp+0xE0], xmm12 movdqa xmmword ptr [rsp+0xF0], xmm13 movdqa xmm9, xmmword ptr [BLAKE3_IV_1+rip] movdqa xmm10, xmmword ptr [BLAKE3_IV_2+rip] movdqa xmm11, xmmword ptr [BLAKE3_IV_3+rip] movdqa xmm12, xmmword ptr [rsp+0x110] movdqa xmm13, xmmword ptr [rsp+0x120] movdqa xmm14, xmmword ptr [BLAKE3_BLOCK_LEN+rip] movd xmm15, eax pshufd xmm15, xmm15, 0x00 prefetcht0 [r8+rdx+0x80] prefetcht0 [r9+rdx+0x80] prefetcht0 [r10+rdx+0x80] prefetcht0 [r11+rdx+0x80] paddd xmm0, xmmword ptr [rsp] paddd xmm1, xmmword ptr [rsp+0x20] paddd xmm2, xmmword ptr [rsp+0x40] paddd xmm3, xmmword ptr [rsp+0x60] paddd xmm0, xmm4 paddd xmm1, xmm5 paddd xmm2, xmm6 paddd xmm3, xmm7 pxor xmm12, xmm0 pxor xmm13, xmm1 pxor xmm14, xmm2 pxor xmm15, xmm3 movdqa xmm8, xmmword ptr [ROT16+rip] pshufb xmm12, xmm8 pshufb xmm13, xmm8 pshufb xmm14, xmm8 pshufb xmm15, xmm8 movdqa xmm8, xmmword ptr [BLAKE3_IV_0+rip] paddd xmm8, xmm12 paddd xmm9, xmm13 paddd xmm10, xmm14 paddd xmm11, xmm15 pxor xmm4, xmm8 pxor xmm5, xmm9 pxor xmm6, xmm10 pxor xmm7, xmm11 movdqa xmmword ptr [rsp+0x100], xmm8 movdqa xmm8, xmm4 psrld xmm8, 12 pslld xmm4, 20 por xmm4, xmm8 movdqa xmm8, xmm5 psrld xmm8, 12 pslld xmm5, 20 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 12 pslld xmm6, 20 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 12 pslld xmm7, 20 por xmm7, xmm8 paddd xmm0, xmmword ptr [rsp+0x10] paddd xmm1, xmmword ptr [rsp+0x30] paddd xmm2, xmmword ptr [rsp+0x50] paddd xmm3, xmmword ptr [rsp+0x70] paddd xmm0, xmm4 paddd xmm1, xmm5 paddd xmm2, xmm6 paddd xmm3, xmm7 pxor xmm12, xmm0 pxor xmm13, xmm1 pxor xmm14, xmm2 pxor xmm15, xmm3 movdqa xmm8, xmmword ptr [ROT8+rip] pshufb xmm12, xmm8 pshufb xmm13, xmm8 pshufb xmm14, xmm8 pshufb xmm15, xmm8 movdqa xmm8, xmmword ptr [rsp+0x100] paddd xmm8, xmm12 paddd xmm9, xmm13 paddd xmm10, xmm14 paddd xmm11, xmm15 pxor xmm4, xmm8 pxor xmm5, xmm9 pxor xmm6, xmm10 pxor xmm7, xmm11 movdqa xmmword ptr [rsp+0x100], xmm8 movdqa xmm8, xmm4 psrld xmm8, 7 pslld xmm4, 25 por xmm4, xmm8 movdqa xmm8, xmm5 psrld xmm8, 7 pslld xmm5, 25 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 7 pslld xmm6, 25 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 7 pslld xmm7, 25 por xmm7, xmm8 paddd xmm0, xmmword ptr [rsp+0x80] paddd xmm1, xmmword ptr [rsp+0xA0] paddd xmm2, xmmword ptr [rsp+0xC0] paddd xmm3, xmmword ptr [rsp+0xE0] paddd xmm0, xmm5 paddd xmm1, xmm6 paddd xmm2, xmm7 paddd xmm3, xmm4 pxor xmm15, xmm0 pxor xmm12, xmm1 pxor xmm13, xmm2 pxor xmm14, xmm3 movdqa xmm8, xmmword ptr [ROT16+rip] pshufb xmm15, xmm8 pshufb xmm12, xmm8 pshufb xmm13, xmm8 pshufb xmm14, xmm8 paddd xmm10, xmm15 paddd xmm11, xmm12 movdqa xmm8, xmmword ptr [rsp+0x100] paddd xmm8, xmm13 paddd xmm9, xmm14 pxor xmm5, xmm10 pxor xmm6, xmm11 pxor xmm7, xmm8 pxor xmm4, xmm9 movdqa xmmword ptr [rsp+0x100], xmm8 movdqa xmm8, xmm5 psrld xmm8, 12 pslld xmm5, 20 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 12 pslld xmm6, 20 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 12 pslld xmm7, 20 por xmm7, xmm8 movdqa xmm8, xmm4 psrld xmm8, 12 pslld xmm4, 20 por xmm4, xmm8 paddd xmm0, xmmword ptr [rsp+0x90] paddd xmm1, xmmword ptr [rsp+0xB0] paddd xmm2, xmmword ptr [rsp+0xD0] paddd xmm3, xmmword ptr [rsp+0xF0] paddd xmm0, xmm5 paddd xmm1, xmm6 paddd xmm2, xmm7 paddd xmm3, xmm4 pxor xmm15, xmm0 pxor xmm12, xmm1 pxor xmm13, xmm2 pxor xmm14, xmm3 movdqa xmm8, xmmword ptr [ROT8+rip] pshufb xmm15, xmm8 pshufb xmm12, xmm8 pshufb xmm13, xmm8 pshufb xmm14, xmm8 paddd xmm10, xmm15 paddd xmm11, xmm12 movdqa xmm8, xmmword ptr [rsp+0x100] paddd xmm8, xmm13 paddd xmm9, xmm14 pxor xmm5, xmm10 pxor xmm6, xmm11 pxor xmm7, xmm8 pxor xmm4, xmm9 movdqa xmmword ptr [rsp+0x100], xmm8 movdqa xmm8, xmm5 psrld xmm8, 7 pslld xmm5, 25 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 7 pslld xmm6, 25 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 7 pslld xmm7, 25 por xmm7, xmm8 movdqa xmm8, xmm4 psrld xmm8, 7 pslld xmm4, 25 por xmm4, xmm8 paddd xmm0, xmmword ptr [rsp+0x20] paddd xmm1, xmmword ptr [rsp+0x30] paddd xmm2, xmmword ptr [rsp+0x70] paddd xmm3, xmmword ptr [rsp+0x40] paddd xmm0, xmm4 paddd xmm1, xmm5 paddd xmm2, xmm6 paddd xmm3, xmm7 pxor xmm12, xmm0 pxor xmm13, xmm1 pxor xmm14, xmm2 pxor xmm15, xmm3 movdqa xmm8, xmmword ptr [ROT16+rip] pshufb xmm12, xmm8 pshufb xmm13, xmm8 pshufb xmm14, xmm8 pshufb xmm15, xmm8 movdqa xmm8, xmmword ptr [rsp+0x100] paddd xmm8, xmm12 paddd xmm9, xmm13 paddd xmm10, xmm14 paddd xmm11, xmm15 pxor xmm4, xmm8 pxor xmm5, xmm9 pxor xmm6, xmm10 pxor xmm7, xmm11 movdqa xmmword ptr [rsp+0x100], xmm8 movdqa xmm8, xmm4 psrld xmm8, 12 pslld xmm4, 20 por xmm4, xmm8 movdqa xmm8, xmm5 psrld xmm8, 12 pslld xmm5, 20 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 12 pslld xmm6, 20 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 12 pslld xmm7, 20 por xmm7, xmm8 paddd xmm0, xmmword ptr [rsp+0x60] paddd xmm1, xmmword ptr [rsp+0xA0] paddd xmm2, xmmword ptr [rsp] paddd xmm3, xmmword ptr [rsp+0xD0] paddd xmm0, xmm4 paddd xmm1, xmm5 paddd xmm2, xmm6 paddd xmm3, xmm7 pxor xmm12, xmm0 pxor xmm13, xmm1 pxor xmm14, xmm2 pxor xmm15, xmm3 movdqa xmm8, xmmword ptr [ROT8+rip] pshufb xmm12, xmm8 pshufb xmm13, xmm8 pshufb xmm14, xmm8 pshufb xmm15, xmm8 movdqa xmm8, xmmword ptr [rsp+0x100] paddd xmm8, xmm12 paddd xmm9, xmm13 paddd xmm10, xmm14 paddd xmm11, xmm15 pxor xmm4, xmm8 pxor xmm5, xmm9 pxor xmm6, xmm10 pxor xmm7, xmm11 movdqa xmmword ptr [rsp+0x100], xmm8 movdqa xmm8, xmm4 psrld xmm8, 7 pslld xmm4, 25 por xmm4, xmm8 movdqa xmm8, xmm5 psrld xmm8, 7 pslld xmm5, 25 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 7 pslld xmm6, 25 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 7 pslld xmm7, 25 por xmm7, xmm8 paddd xmm0, xmmword ptr [rsp+0x10] paddd xmm1, xmmword ptr [rsp+0xC0] paddd xmm2, xmmword ptr [rsp+0x90] paddd xmm3, xmmword ptr [rsp+0xF0] paddd xmm0, xmm5 paddd xmm1, xmm6 paddd xmm2, xmm7 paddd xmm3, xmm4 pxor xmm15, xmm0 pxor xmm12, xmm1 pxor xmm13, xmm2 pxor xmm14, xmm3 movdqa xmm8, xmmword ptr [ROT16+rip] pshufb xmm15, xmm8 pshufb xmm12, xmm8 pshufb xmm13, xmm8 pshufb xmm14, xmm8 paddd xmm10, xmm15 paddd xmm11, xmm12 movdqa xmm8, xmmword ptr [rsp+0x100] paddd xmm8, xmm13 paddd xmm9, xmm14 pxor xmm5, xmm10 pxor xmm6, xmm11 pxor xmm7, xmm8 pxor xmm4, xmm9 movdqa xmmword ptr [rsp+0x100], xmm8 movdqa xmm8, xmm5 psrld xmm8, 12 pslld xmm5, 20 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 12 pslld xmm6, 20 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 12 pslld xmm7, 20 por xmm7, xmm8 movdqa xmm8, xmm4 psrld xmm8, 12 pslld xmm4, 20 por xmm4, xmm8 paddd xmm0, xmmword ptr [rsp+0xB0] paddd xmm1, xmmword ptr [rsp+0x50] paddd xmm2, xmmword ptr [rsp+0xE0] paddd xmm3, xmmword ptr [rsp+0x80] paddd xmm0, xmm5 paddd xmm1, xmm6 paddd xmm2, xmm7 paddd xmm3, xmm4 pxor xmm15, xmm0 pxor xmm12, xmm1 pxor xmm13, xmm2 pxor xmm14, xmm3 movdqa xmm8, xmmword ptr [ROT8+rip] pshufb xmm15, xmm8 pshufb xmm12, xmm8 pshufb xmm13, xmm8 pshufb xmm14, xmm8 paddd xmm10, xmm15 paddd xmm11, xmm12 movdqa xmm8, xmmword ptr [rsp+0x100] paddd xmm8, xmm13 paddd xmm9, xmm14 pxor xmm5, xmm10 pxor xmm6, xmm11 pxor xmm7, xmm8 pxor xmm4, xmm9 movdqa xmmword ptr [rsp+0x100], xmm8 movdqa xmm8, xmm5 psrld xmm8, 7 pslld xmm5, 25 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 7 pslld xmm6, 25 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 7 pslld xmm7, 25 por xmm7, xmm8 movdqa xmm8, xmm4 psrld xmm8, 7 pslld xmm4, 25 por xmm4, xmm8 paddd xmm0, xmmword ptr [rsp+0x30] paddd xmm1, xmmword ptr [rsp+0xA0] paddd xmm2, xmmword ptr [rsp+0xD0] paddd xmm3, xmmword ptr [rsp+0x70] paddd xmm0, xmm4 paddd xmm1, xmm5 paddd xmm2, xmm6 paddd xmm3, xmm7 pxor xmm12, xmm0 pxor xmm13, xmm1 pxor xmm14, xmm2 pxor xmm15, xmm3 movdqa xmm8, xmmword ptr [ROT16+rip] pshufb xmm12, xmm8 pshufb xmm13, xmm8 pshufb xmm14, xmm8 pshufb xmm15, xmm8 movdqa xmm8, xmmword ptr [rsp+0x100] paddd xmm8, xmm12 paddd xmm9, xmm13 paddd xmm10, xmm14 paddd xmm11, xmm15 pxor xmm4, xmm8 pxor xmm5, xmm9 pxor xmm6, xmm10 pxor xmm7, xmm11 movdqa xmmword ptr [rsp+0x100], xmm8 movdqa xmm8, xmm4 psrld xmm8, 12 pslld xmm4, 20 por xmm4, xmm8 movdqa xmm8, xmm5 psrld xmm8, 12 pslld xmm5, 20 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 12 pslld xmm6, 20 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 12 pslld xmm7, 20 por xmm7, xmm8 paddd xmm0, xmmword ptr [rsp+0x40] paddd xmm1, xmmword ptr [rsp+0xC0] paddd xmm2, xmmword ptr [rsp+0x20] paddd xmm3, xmmword ptr [rsp+0xE0] paddd xmm0, xmm4 paddd xmm1, xmm5 paddd xmm2, xmm6 paddd xmm3, xmm7 pxor xmm12, xmm0 pxor xmm13, xmm1 pxor xmm14, xmm2 pxor xmm15, xmm3 movdqa xmm8, xmmword ptr [ROT8+rip] pshufb xmm12, xmm8 pshufb xmm13, xmm8 pshufb xmm14, xmm8 pshufb xmm15, xmm8 movdqa xmm8, xmmword ptr [rsp+0x100] paddd xmm8, xmm12 paddd xmm9, xmm13 paddd xmm10, xmm14 paddd xmm11, xmm15 pxor xmm4, xmm8 pxor xmm5, xmm9 pxor xmm6, xmm10 pxor xmm7, xmm11 movdqa xmmword ptr [rsp+0x100], xmm8 movdqa xmm8, xmm4 psrld xmm8, 7 pslld xmm4, 25 por xmm4, xmm8 movdqa xmm8, xmm5 psrld xmm8, 7 pslld xmm5, 25 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 7 pslld xmm6, 25 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 7 pslld xmm7, 25 por xmm7, xmm8 paddd xmm0, xmmword ptr [rsp+0x60] paddd xmm1, xmmword ptr [rsp+0x90] paddd xmm2, xmmword ptr [rsp+0xB0] paddd xmm3, xmmword ptr [rsp+0x80] paddd xmm0, xmm5 paddd xmm1, xmm6 paddd xmm2, xmm7 paddd xmm3, xmm4 pxor xmm15, xmm0 pxor xmm12, xmm1 pxor xmm13, xmm2 pxor xmm14, xmm3 movdqa xmm8, xmmword ptr [ROT16+rip] pshufb xmm15, xmm8 pshufb xmm12, xmm8 pshufb xmm13, xmm8 pshufb xmm14, xmm8 paddd xmm10, xmm15 paddd xmm11, xmm12 movdqa xmm8, xmmword ptr [rsp+0x100] paddd xmm8, xmm13 paddd xmm9, xmm14 pxor xmm5, xmm10 pxor xmm6, xmm11 pxor xmm7, xmm8 pxor xmm4, xmm9 movdqa xmmword ptr [rsp+0x100], xmm8 movdqa xmm8, xmm5 psrld xmm8, 12 pslld xmm5, 20 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 12 pslld xmm6, 20 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 12 pslld xmm7, 20 por xmm7, xmm8 movdqa xmm8, xmm4 psrld xmm8, 12 pslld xmm4, 20 por xmm4, xmm8 paddd xmm0, xmmword ptr [rsp+0x50] paddd xmm1, xmmword ptr [rsp] paddd xmm2, xmmword ptr [rsp+0xF0] paddd xmm3, xmmword ptr [rsp+0x10] paddd xmm0, xmm5 paddd xmm1, xmm6 paddd xmm2, xmm7 paddd xmm3, xmm4 pxor xmm15, xmm0 pxor xmm12, xmm1 pxor xmm13, xmm2 pxor xmm14, xmm3 movdqa xmm8, xmmword ptr [ROT8+rip] pshufb xmm15, xmm8 pshufb xmm12, xmm8 pshufb xmm13, xmm8 pshufb xmm14, xmm8 paddd xmm10, xmm15 paddd xmm11, xmm12 movdqa xmm8, xmmword ptr [rsp+0x100] paddd xmm8, xmm13 paddd xmm9, xmm14 pxor xmm5, xmm10 pxor xmm6, xmm11 pxor xmm7, xmm8 pxor xmm4, xmm9 movdqa xmmword ptr [rsp+0x100], xmm8 movdqa xmm8, xmm5 psrld xmm8, 7 pslld xmm5, 25 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 7 pslld xmm6, 25 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 7 pslld xmm7, 25 por xmm7, xmm8 movdqa xmm8, xmm4 psrld xmm8, 7 pslld xmm4, 25 por xmm4, xmm8 paddd xmm0, xmmword ptr [rsp+0xA0] paddd xmm1, xmmword ptr [rsp+0xC0] paddd xmm2, xmmword ptr [rsp+0xE0] paddd xmm3, xmmword ptr [rsp+0xD0] paddd xmm0, xmm4 paddd xmm1, xmm5 paddd xmm2, xmm6 paddd xmm3, xmm7 pxor xmm12, xmm0 pxor xmm13, xmm1 pxor xmm14, xmm2 pxor xmm15, xmm3 movdqa xmm8, xmmword ptr [ROT16+rip] pshufb xmm12, xmm8 pshufb xmm13, xmm8 pshufb xmm14, xmm8 pshufb xmm15, xmm8 movdqa xmm8, xmmword ptr [rsp+0x100] paddd xmm8, xmm12 paddd xmm9, xmm13 paddd xmm10, xmm14 paddd xmm11, xmm15 pxor xmm4, xmm8 pxor xmm5, xmm9 pxor xmm6, xmm10 pxor xmm7, xmm11 movdqa xmmword ptr [rsp+0x100], xmm8 movdqa xmm8, xmm4 psrld xmm8, 12 pslld xmm4, 20 por xmm4, xmm8 movdqa xmm8, xmm5 psrld xmm8, 12 pslld xmm5, 20 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 12 pslld xmm6, 20 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 12 pslld xmm7, 20 por xmm7, xmm8 paddd xmm0, xmmword ptr [rsp+0x70] paddd xmm1, xmmword ptr [rsp+0x90] paddd xmm2, xmmword ptr [rsp+0x30] paddd xmm3, xmmword ptr [rsp+0xF0] paddd xmm0, xmm4 paddd xmm1, xmm5 paddd xmm2, xmm6 paddd xmm3, xmm7 pxor xmm12, xmm0 pxor xmm13, xmm1 pxor xmm14, xmm2 pxor xmm15, xmm3 movdqa xmm8, xmmword ptr [ROT8+rip] pshufb xmm12, xmm8 pshufb xmm13, xmm8 pshufb xmm14, xmm8 pshufb xmm15, xmm8 movdqa xmm8, xmmword ptr [rsp+0x100] paddd xmm8, xmm12 paddd xmm9, xmm13 paddd xmm10, xmm14 paddd xmm11, xmm15 pxor xmm4, xmm8 pxor xmm5, xmm9 pxor xmm6, xmm10 pxor xmm7, xmm11 movdqa xmmword ptr [rsp+0x100], xmm8 movdqa xmm8, xmm4 psrld xmm8, 7 pslld xmm4, 25 por xmm4, xmm8 movdqa xmm8, xmm5 psrld xmm8, 7 pslld xmm5, 25 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 7 pslld xmm6, 25 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 7 pslld xmm7, 25 por xmm7, xmm8 paddd xmm0, xmmword ptr [rsp+0x40] paddd xmm1, xmmword ptr [rsp+0xB0] paddd xmm2, xmmword ptr [rsp+0x50] paddd xmm3, xmmword ptr [rsp+0x10] paddd xmm0, xmm5 paddd xmm1, xmm6 paddd xmm2, xmm7 paddd xmm3, xmm4 pxor xmm15, xmm0 pxor xmm12, xmm1 pxor xmm13, xmm2 pxor xmm14, xmm3 movdqa xmm8, xmmword ptr [ROT16+rip] pshufb xmm15, xmm8 pshufb xmm12, xmm8 pshufb xmm13, xmm8 pshufb xmm14, xmm8 paddd xmm10, xmm15 paddd xmm11, xmm12 movdqa xmm8, xmmword ptr [rsp+0x100] paddd xmm8, xmm13 paddd xmm9, xmm14 pxor xmm5, xmm10 pxor xmm6, xmm11 pxor xmm7, xmm8 pxor xmm4, xmm9 movdqa xmmword ptr [rsp+0x100], xmm8 movdqa xmm8, xmm5 psrld xmm8, 12 pslld xmm5, 20 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 12 pslld xmm6, 20 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 12 pslld xmm7, 20 por xmm7, xmm8 movdqa xmm8, xmm4 psrld xmm8, 12 pslld xmm4, 20 por xmm4, xmm8 paddd xmm0, xmmword ptr [rsp] paddd xmm1, xmmword ptr [rsp+0x20] paddd xmm2, xmmword ptr [rsp+0x80] paddd xmm3, xmmword ptr [rsp+0x60] paddd xmm0, xmm5 paddd xmm1, xmm6 paddd xmm2, xmm7 paddd xmm3, xmm4 pxor xmm15, xmm0 pxor xmm12, xmm1 pxor xmm13, xmm2 pxor xmm14, xmm3 movdqa xmm8, xmmword ptr [ROT8+rip] pshufb xmm15, xmm8 pshufb xmm12, xmm8 pshufb xmm13, xmm8 pshufb xmm14, xmm8 paddd xmm10, xmm15 paddd xmm11, xmm12 movdqa xmm8, xmmword ptr [rsp+0x100] paddd xmm8, xmm13 paddd xmm9, xmm14 pxor xmm5, xmm10 pxor xmm6, xmm11 pxor xmm7, xmm8 pxor xmm4, xmm9 movdqa xmmword ptr [rsp+0x100], xmm8 movdqa xmm8, xmm5 psrld xmm8, 7 pslld xmm5, 25 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 7 pslld xmm6, 25 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 7 pslld xmm7, 25 por xmm7, xmm8 movdqa xmm8, xmm4 psrld xmm8, 7 pslld xmm4, 25 por xmm4, xmm8 paddd xmm0, xmmword ptr [rsp+0xC0] paddd xmm1, xmmword ptr [rsp+0x90] paddd xmm2, xmmword ptr [rsp+0xF0] paddd xmm3, xmmword ptr [rsp+0xE0] paddd xmm0, xmm4 paddd xmm1, xmm5 paddd xmm2, xmm6 paddd xmm3, xmm7 pxor xmm12, xmm0 pxor xmm13, xmm1 pxor xmm14, xmm2 pxor xmm15, xmm3 movdqa xmm8, xmmword ptr [ROT16+rip] pshufb xmm12, xmm8 pshufb xmm13, xmm8 pshufb xmm14, xmm8 pshufb xmm15, xmm8 movdqa xmm8, xmmword ptr [rsp+0x100] paddd xmm8, xmm12 paddd xmm9, xmm13 paddd xmm10, xmm14 paddd xmm11, xmm15 pxor xmm4, xmm8 pxor xmm5, xmm9 pxor xmm6, xmm10 pxor xmm7, xmm11 movdqa xmmword ptr [rsp+0x100], xmm8 movdqa xmm8, xmm4 psrld xmm8, 12 pslld xmm4, 20 por xmm4, xmm8 movdqa xmm8, xmm5 psrld xmm8, 12 pslld xmm5, 20 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 12 pslld xmm6, 20 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 12 pslld xmm7, 20 por xmm7, xmm8 paddd xmm0, xmmword ptr [rsp+0xD0] paddd xmm1, xmmword ptr [rsp+0xB0] paddd xmm2, xmmword ptr [rsp+0xA0] paddd xmm3, xmmword ptr [rsp+0x80] paddd xmm0, xmm4 paddd xmm1, xmm5 paddd xmm2, xmm6 paddd xmm3, xmm7 pxor xmm12, xmm0 pxor xmm13, xmm1 pxor xmm14, xmm2 pxor xmm15, xmm3 movdqa xmm8, xmmword ptr [ROT8+rip] pshufb xmm12, xmm8 pshufb xmm13, xmm8 pshufb xmm14, xmm8 pshufb xmm15, xmm8 movdqa xmm8, xmmword ptr [rsp+0x100] paddd xmm8, xmm12 paddd xmm9, xmm13 paddd xmm10, xmm14 paddd xmm11, xmm15 pxor xmm4, xmm8 pxor xmm5, xmm9 pxor xmm6, xmm10 pxor xmm7, xmm11 movdqa xmmword ptr [rsp+0x100], xmm8 movdqa xmm8, xmm4 psrld xmm8, 7 pslld xmm4, 25 por xmm4, xmm8 movdqa xmm8, xmm5 psrld xmm8, 7 pslld xmm5, 25 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 7 pslld xmm6, 25 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 7 pslld xmm7, 25 por xmm7, xmm8 paddd xmm0, xmmword ptr [rsp+0x70] paddd xmm1, xmmword ptr [rsp+0x50] paddd xmm2, xmmword ptr [rsp] paddd xmm3, xmmword ptr [rsp+0x60] paddd xmm0, xmm5 paddd xmm1, xmm6 paddd xmm2, xmm7 paddd xmm3, xmm4 pxor xmm15, xmm0 pxor xmm12, xmm1 pxor xmm13, xmm2 pxor xmm14, xmm3 movdqa xmm8, xmmword ptr [ROT16+rip] pshufb xmm15, xmm8 pshufb xmm12, xmm8 pshufb xmm13, xmm8 pshufb xmm14, xmm8 paddd xmm10, xmm15 paddd xmm11, xmm12 movdqa xmm8, xmmword ptr [rsp+0x100] paddd xmm8, xmm13 paddd xmm9, xmm14 pxor xmm5, xmm10 pxor xmm6, xmm11 pxor xmm7, xmm8 pxor xmm4, xmm9 movdqa xmmword ptr [rsp+0x100], xmm8 movdqa xmm8, xmm5 psrld xmm8, 12 pslld xmm5, 20 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 12 pslld xmm6, 20 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 12 pslld xmm7, 20 por xmm7, xmm8 movdqa xmm8, xmm4 psrld xmm8, 12 pslld xmm4, 20 por xmm4, xmm8 paddd xmm0, xmmword ptr [rsp+0x20] paddd xmm1, xmmword ptr [rsp+0x30] paddd xmm2, xmmword ptr [rsp+0x10] paddd xmm3, xmmword ptr [rsp+0x40] paddd xmm0, xmm5 paddd xmm1, xmm6 paddd xmm2, xmm7 paddd xmm3, xmm4 pxor xmm15, xmm0 pxor xmm12, xmm1 pxor xmm13, xmm2 pxor xmm14, xmm3 movdqa xmm8, xmmword ptr [ROT8+rip] pshufb xmm15, xmm8 pshufb xmm12, xmm8 pshufb xmm13, xmm8 pshufb xmm14, xmm8 paddd xmm10, xmm15 paddd xmm11, xmm12 movdqa xmm8, xmmword ptr [rsp+0x100] paddd xmm8, xmm13 paddd xmm9, xmm14 pxor xmm5, xmm10 pxor xmm6, xmm11 pxor xmm7, xmm8 pxor xmm4, xmm9 movdqa xmmword ptr [rsp+0x100], xmm8 movdqa xmm8, xmm5 psrld xmm8, 7 pslld xmm5, 25 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 7 pslld xmm6, 25 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 7 pslld xmm7, 25 por xmm7, xmm8 movdqa xmm8, xmm4 psrld xmm8, 7 pslld xmm4, 25 por xmm4, xmm8 paddd xmm0, xmmword ptr [rsp+0x90] paddd xmm1, xmmword ptr [rsp+0xB0] paddd xmm2, xmmword ptr [rsp+0x80] paddd xmm3, xmmword ptr [rsp+0xF0] paddd xmm0, xmm4 paddd xmm1, xmm5 paddd xmm2, xmm6 paddd xmm3, xmm7 pxor xmm12, xmm0 pxor xmm13, xmm1 pxor xmm14, xmm2 pxor xmm15, xmm3 movdqa xmm8, xmmword ptr [ROT16+rip] pshufb xmm12, xmm8 pshufb xmm13, xmm8 pshufb xmm14, xmm8 pshufb xmm15, xmm8 movdqa xmm8, xmmword ptr [rsp+0x100] paddd xmm8, xmm12 paddd xmm9, xmm13 paddd xmm10, xmm14 paddd xmm11, xmm15 pxor xmm4, xmm8 pxor xmm5, xmm9 pxor xmm6, xmm10 pxor xmm7, xmm11 movdqa xmmword ptr [rsp+0x100], xmm8 movdqa xmm8, xmm4 psrld xmm8, 12 pslld xmm4, 20 por xmm4, xmm8 movdqa xmm8, xmm5 psrld xmm8, 12 pslld xmm5, 20 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 12 pslld xmm6, 20 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 12 pslld xmm7, 20 por xmm7, xmm8 paddd xmm0, xmmword ptr [rsp+0xE0] paddd xmm1, xmmword ptr [rsp+0x50] paddd xmm2, xmmword ptr [rsp+0xC0] paddd xmm3, xmmword ptr [rsp+0x10] paddd xmm0, xmm4 paddd xmm1, xmm5 paddd xmm2, xmm6 paddd xmm3, xmm7 pxor xmm12, xmm0 pxor xmm13, xmm1 pxor xmm14, xmm2 pxor xmm15, xmm3 movdqa xmm8, xmmword ptr [ROT8+rip] pshufb xmm12, xmm8 pshufb xmm13, xmm8 pshufb xmm14, xmm8 pshufb xmm15, xmm8 movdqa xmm8, xmmword ptr [rsp+0x100] paddd xmm8, xmm12 paddd xmm9, xmm13 paddd xmm10, xmm14 paddd xmm11, xmm15 pxor xmm4, xmm8 pxor xmm5, xmm9 pxor xmm6, xmm10 pxor xmm7, xmm11 movdqa xmmword ptr [rsp+0x100], xmm8 movdqa xmm8, xmm4 psrld xmm8, 7 pslld xmm4, 25 por xmm4, xmm8 movdqa xmm8, xmm5 psrld xmm8, 7 pslld xmm5, 25 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 7 pslld xmm6, 25 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 7 pslld xmm7, 25 por xmm7, xmm8 paddd xmm0, xmmword ptr [rsp+0xD0] paddd xmm1, xmmword ptr [rsp] paddd xmm2, xmmword ptr [rsp+0x20] paddd xmm3, xmmword ptr [rsp+0x40] paddd xmm0, xmm5 paddd xmm1, xmm6 paddd xmm2, xmm7 paddd xmm3, xmm4 pxor xmm15, xmm0 pxor xmm12, xmm1 pxor xmm13, xmm2 pxor xmm14, xmm3 movdqa xmm8, xmmword ptr [ROT16+rip] pshufb xmm15, xmm8 pshufb xmm12, xmm8 pshufb xmm13, xmm8 pshufb xmm14, xmm8 paddd xmm10, xmm15 paddd xmm11, xmm12 movdqa xmm8, xmmword ptr [rsp+0x100] paddd xmm8, xmm13 paddd xmm9, xmm14 pxor xmm5, xmm10 pxor xmm6, xmm11 pxor xmm7, xmm8 pxor xmm4, xmm9 movdqa xmmword ptr [rsp+0x100], xmm8 movdqa xmm8, xmm5 psrld xmm8, 12 pslld xmm5, 20 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 12 pslld xmm6, 20 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 12 pslld xmm7, 20 por xmm7, xmm8 movdqa xmm8, xmm4 psrld xmm8, 12 pslld xmm4, 20 por xmm4, xmm8 paddd xmm0, xmmword ptr [rsp+0x30] paddd xmm1, xmmword ptr [rsp+0xA0] paddd xmm2, xmmword ptr [rsp+0x60] paddd xmm3, xmmword ptr [rsp+0x70] paddd xmm0, xmm5 paddd xmm1, xmm6 paddd xmm2, xmm7 paddd xmm3, xmm4 pxor xmm15, xmm0 pxor xmm12, xmm1 pxor xmm13, xmm2 pxor xmm14, xmm3 movdqa xmm8, xmmword ptr [ROT8+rip] pshufb xmm15, xmm8 pshufb xmm12, xmm8 pshufb xmm13, xmm8 pshufb xmm14, xmm8 paddd xmm10, xmm15 paddd xmm11, xmm12 movdqa xmm8, xmmword ptr [rsp+0x100] paddd xmm8, xmm13 paddd xmm9, xmm14 pxor xmm5, xmm10 pxor xmm6, xmm11 pxor xmm7, xmm8 pxor xmm4, xmm9 movdqa xmmword ptr [rsp+0x100], xmm8 movdqa xmm8, xmm5 psrld xmm8, 7 pslld xmm5, 25 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 7 pslld xmm6, 25 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 7 pslld xmm7, 25 por xmm7, xmm8 movdqa xmm8, xmm4 psrld xmm8, 7 pslld xmm4, 25 por xmm4, xmm8 paddd xmm0, xmmword ptr [rsp+0xB0] paddd xmm1, xmmword ptr [rsp+0x50] paddd xmm2, xmmword ptr [rsp+0x10] paddd xmm3, xmmword ptr [rsp+0x80] paddd xmm0, xmm4 paddd xmm1, xmm5 paddd xmm2, xmm6 paddd xmm3, xmm7 pxor xmm12, xmm0 pxor xmm13, xmm1 pxor xmm14, xmm2 pxor xmm15, xmm3 movdqa xmm8, xmmword ptr [ROT16+rip] pshufb xmm12, xmm8 pshufb xmm13, xmm8 pshufb xmm14, xmm8 pshufb xmm15, xmm8 movdqa xmm8, xmmword ptr [rsp+0x100] paddd xmm8, xmm12 paddd xmm9, xmm13 paddd xmm10, xmm14 paddd xmm11, xmm15 pxor xmm4, xmm8 pxor xmm5, xmm9 pxor xmm6, xmm10 pxor xmm7, xmm11 movdqa xmmword ptr [rsp+0x100], xmm8 movdqa xmm8, xmm4 psrld xmm8, 12 pslld xmm4, 20 por xmm4, xmm8 movdqa xmm8, xmm5 psrld xmm8, 12 pslld xmm5, 20 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 12 pslld xmm6, 20 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 12 pslld xmm7, 20 por xmm7, xmm8 paddd xmm0, xmmword ptr [rsp+0xF0] paddd xmm1, xmmword ptr [rsp] paddd xmm2, xmmword ptr [rsp+0x90] paddd xmm3, xmmword ptr [rsp+0x60] paddd xmm0, xmm4 paddd xmm1, xmm5 paddd xmm2, xmm6 paddd xmm3, xmm7 pxor xmm12, xmm0 pxor xmm13, xmm1 pxor xmm14, xmm2 pxor xmm15, xmm3 movdqa xmm8, xmmword ptr [ROT8+rip] pshufb xmm12, xmm8 pshufb xmm13, xmm8 pshufb xmm14, xmm8 pshufb xmm15, xmm8 movdqa xmm8, xmmword ptr [rsp+0x100] paddd xmm8, xmm12 paddd xmm9, xmm13 paddd xmm10, xmm14 paddd xmm11, xmm15 pxor xmm4, xmm8 pxor xmm5, xmm9 pxor xmm6, xmm10 pxor xmm7, xmm11 movdqa xmmword ptr [rsp+0x100], xmm8 movdqa xmm8, xmm4 psrld xmm8, 7 pslld xmm4, 25 por xmm4, xmm8 movdqa xmm8, xmm5 psrld xmm8, 7 pslld xmm5, 25 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 7 pslld xmm6, 25 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 7 pslld xmm7, 25 por xmm7, xmm8 paddd xmm0, xmmword ptr [rsp+0xE0] paddd xmm1, xmmword ptr [rsp+0x20] paddd xmm2, xmmword ptr [rsp+0x30] paddd xmm3, xmmword ptr [rsp+0x70] paddd xmm0, xmm5 paddd xmm1, xmm6 paddd xmm2, xmm7 paddd xmm3, xmm4 pxor xmm15, xmm0 pxor xmm12, xmm1 pxor xmm13, xmm2 pxor xmm14, xmm3 movdqa xmm8, xmmword ptr [ROT16+rip] pshufb xmm15, xmm8 pshufb xmm12, xmm8 pshufb xmm13, xmm8 pshufb xmm14, xmm8 paddd xmm10, xmm15 paddd xmm11, xmm12 movdqa xmm8, xmmword ptr [rsp+0x100] paddd xmm8, xmm13 paddd xmm9, xmm14 pxor xmm5, xmm10 pxor xmm6, xmm11 pxor xmm7, xmm8 pxor xmm4, xmm9 movdqa xmmword ptr [rsp+0x100], xmm8 movdqa xmm8, xmm5 psrld xmm8, 12 pslld xmm5, 20 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 12 pslld xmm6, 20 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 12 pslld xmm7, 20 por xmm7, xmm8 movdqa xmm8, xmm4 psrld xmm8, 12 pslld xmm4, 20 por xmm4, xmm8 paddd xmm0, xmmword ptr [rsp+0xA0] paddd xmm1, xmmword ptr [rsp+0xC0] paddd xmm2, xmmword ptr [rsp+0x40] paddd xmm3, xmmword ptr [rsp+0xD0] paddd xmm0, xmm5 paddd xmm1, xmm6 paddd xmm2, xmm7 paddd xmm3, xmm4 pxor xmm15, xmm0 pxor xmm12, xmm1 pxor xmm13, xmm2 pxor xmm14, xmm3 movdqa xmm8, xmmword ptr [ROT8+rip] pshufb xmm15, xmm8 pshufb xmm12, xmm8 pshufb xmm13, xmm8 pshufb xmm14, xmm8 paddd xmm10, xmm15 paddd xmm11, xmm12 movdqa xmm8, xmmword ptr [rsp+0x100] paddd xmm8, xmm13 paddd xmm9, xmm14 pxor xmm5, xmm10 pxor xmm6, xmm11 pxor xmm7, xmm8 pxor xmm4, xmm9 pxor xmm0, xmm8 pxor xmm1, xmm9 pxor xmm2, xmm10 pxor xmm3, xmm11 movdqa xmm8, xmm5 psrld xmm8, 7 pslld xmm5, 25 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 7 pslld xmm6, 25 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 7 pslld xmm7, 25 por xmm7, xmm8 movdqa xmm8, xmm4 psrld xmm8, 7 pslld xmm4, 25 por xmm4, xmm8 pxor xmm4, xmm12 pxor xmm5, xmm13 pxor xmm6, xmm14 pxor xmm7, xmm15 mov eax, r13d jne 9b movdqa xmm9, xmm0 punpckldq xmm0, xmm1 punpckhdq xmm9, xmm1 movdqa xmm11, xmm2 punpckldq xmm2, xmm3 punpckhdq xmm11, xmm3 movdqa xmm1, xmm0 punpcklqdq xmm0, xmm2 punpckhqdq xmm1, xmm2 movdqa xmm3, xmm9 punpcklqdq xmm9, xmm11 punpckhqdq xmm3, xmm11 movdqu xmmword ptr [rbx], xmm0 movdqu xmmword ptr [rbx+0x20], xmm1 movdqu xmmword ptr [rbx+0x40], xmm9 movdqu xmmword ptr [rbx+0x60], xmm3 movdqa xmm9, xmm4 punpckldq xmm4, xmm5 punpckhdq xmm9, xmm5 movdqa xmm11, xmm6 punpckldq xmm6, xmm7 punpckhdq xmm11, xmm7 movdqa xmm5, xmm4 punpcklqdq xmm4, xmm6 punpckhqdq xmm5, xmm6 movdqa xmm7, xmm9 punpcklqdq xmm9, xmm11 punpckhqdq xmm7, xmm11 movdqu xmmword ptr [rbx+0x10], xmm4 movdqu xmmword ptr [rbx+0x30], xmm5 movdqu xmmword ptr [rbx+0x50], xmm9 movdqu xmmword ptr [rbx+0x70], xmm7 movdqa xmm1, xmmword ptr [rsp+0x110] movdqa xmm0, xmm1 paddd xmm1, xmmword ptr [rsp+0x150] movdqa xmmword ptr [rsp+0x110], xmm1 pxor xmm0, xmmword ptr [CMP_MSB_MASK+rip] pxor xmm1, xmmword ptr [CMP_MSB_MASK+rip] pcmpgtd xmm0, xmm1 movdqa xmm1, xmmword ptr [rsp+0x120] psubd xmm1, xmm0 movdqa xmmword ptr [rsp+0x120], xmm1 add rbx, 128 add rdi, 32 sub rsi, 4 cmp rsi, 4 jnc 2b test rsi, rsi jnz 3f 4: mov rsp, rbp pop rbp pop rbx pop r12 pop r13 pop r14 pop r15 ret .p2align 5 3: test esi, 0x2 je 3f movups xmm0, xmmword ptr [rcx] movups xmm1, xmmword ptr [rcx+0x10] movaps xmm8, xmm0 movaps xmm9, xmm1 movd xmm13, dword ptr [rsp+0x110] pinsrd xmm13, dword ptr [rsp+0x120], 1 pinsrd xmm13, dword ptr [BLAKE3_BLOCK_LEN+rip], 2 movaps xmmword ptr [rsp], xmm13 movd xmm14, dword ptr [rsp+0x114] pinsrd xmm14, dword ptr [rsp+0x124], 1 pinsrd xmm14, dword ptr [BLAKE3_BLOCK_LEN+rip], 2 movaps xmmword ptr [rsp+0x10], xmm14 mov r8, qword ptr [rdi] mov r9, qword ptr [rdi+0x8] movzx eax, byte ptr [rbp+0x40] or eax, r13d xor edx, edx 2: mov r14d, eax or eax, r12d add rdx, 64 cmp rdx, r15 cmovne eax, r14d movaps xmm2, xmmword ptr [BLAKE3_IV+rip] movaps xmm10, xmm2 movups xmm4, xmmword ptr [r8+rdx-0x40] movups xmm5, xmmword ptr [r8+rdx-0x30] movaps xmm3, xmm4 shufps xmm4, xmm5, 136 shufps xmm3, xmm5, 221 movaps xmm5, xmm3 movups xmm6, xmmword ptr [r8+rdx-0x20] movups xmm7, xmmword ptr [r8+rdx-0x10] movaps xmm3, xmm6 shufps xmm6, xmm7, 136 pshufd xmm6, xmm6, 0x93 shufps xmm3, xmm7, 221 pshufd xmm7, xmm3, 0x93 movups xmm12, xmmword ptr [r9+rdx-0x40] movups xmm13, xmmword ptr [r9+rdx-0x30] movaps xmm11, xmm12 shufps xmm12, xmm13, 136 shufps xmm11, xmm13, 221 movaps xmm13, xmm11 movups xmm14, xmmword ptr [r9+rdx-0x20] movups xmm15, xmmword ptr [r9+rdx-0x10] movaps xmm11, xmm14 shufps xmm14, xmm15, 136 pshufd xmm14, xmm14, 0x93 shufps xmm11, xmm15, 221 pshufd xmm15, xmm11, 0x93 movaps xmm3, xmmword ptr [rsp] movaps xmm11, xmmword ptr [rsp+0x10] pinsrd xmm3, eax, 3 pinsrd xmm11, eax, 3 mov al, 7 9: paddd xmm0, xmm4 paddd xmm8, xmm12 movaps xmmword ptr [rsp+0x20], xmm4 movaps xmmword ptr [rsp+0x30], xmm12 paddd xmm0, xmm1 paddd xmm8, xmm9 pxor xmm3, xmm0 pxor xmm11, xmm8 movaps xmm12, xmmword ptr [ROT16+rip] pshufb xmm3, xmm12 pshufb xmm11, xmm12 paddd xmm2, xmm3 paddd xmm10, xmm11 pxor xmm1, xmm2 pxor xmm9, xmm10 movdqa xmm4, xmm1 pslld xmm1, 20 psrld xmm4, 12 por xmm1, xmm4 movdqa xmm4, xmm9 pslld xmm9, 20 psrld xmm4, 12 por xmm9, xmm4 paddd xmm0, xmm5 paddd xmm8, xmm13 movaps xmmword ptr [rsp+0x40], xmm5 movaps xmmword ptr [rsp+0x50], xmm13 paddd xmm0, xmm1 paddd xmm8, xmm9 pxor xmm3, xmm0 pxor xmm11, xmm8 movaps xmm13, xmmword ptr [ROT8+rip] pshufb xmm3, xmm13 pshufb xmm11, xmm13 paddd xmm2, xmm3 paddd xmm10, xmm11 pxor xmm1, xmm2 pxor xmm9, xmm10 movdqa xmm4, xmm1 pslld xmm1, 25 psrld xmm4, 7 por xmm1, xmm4 movdqa xmm4, xmm9 pslld xmm9, 25 psrld xmm4, 7 por xmm9, xmm4 pshufd xmm0, xmm0, 0x93 pshufd xmm8, xmm8, 0x93 pshufd xmm3, xmm3, 0x4E pshufd xmm11, xmm11, 0x4E pshufd xmm2, xmm2, 0x39 pshufd xmm10, xmm10, 0x39 paddd xmm0, xmm6 paddd xmm8, xmm14 paddd xmm0, xmm1 paddd xmm8, xmm9 pxor xmm3, xmm0 pxor xmm11, xmm8 pshufb xmm3, xmm12 pshufb xmm11, xmm12 paddd xmm2, xmm3 paddd xmm10, xmm11 pxor xmm1, xmm2 pxor xmm9, xmm10 movdqa xmm4, xmm1 pslld xmm1, 20 psrld xmm4, 12 por xmm1, xmm4 movdqa xmm4, xmm9 pslld xmm9, 20 psrld xmm4, 12 por xmm9, xmm4 paddd xmm0, xmm7 paddd xmm8, xmm15 paddd xmm0, xmm1 paddd xmm8, xmm9 pxor xmm3, xmm0 pxor xmm11, xmm8 pshufb xmm3, xmm13 pshufb xmm11, xmm13 paddd xmm2, xmm3 paddd xmm10, xmm11 pxor xmm1, xmm2 pxor xmm9, xmm10 movdqa xmm4, xmm1 pslld xmm1, 25 psrld xmm4, 7 por xmm1, xmm4 movdqa xmm4, xmm9 pslld xmm9, 25 psrld xmm4, 7 por xmm9, xmm4 pshufd xmm0, xmm0, 0x39 pshufd xmm8, xmm8, 0x39 pshufd xmm3, xmm3, 0x4E pshufd xmm11, xmm11, 0x4E pshufd xmm2, xmm2, 0x93 pshufd xmm10, xmm10, 0x93 dec al je 9f movdqa xmm12, xmmword ptr [rsp+0x20] movdqa xmm5, xmmword ptr [rsp+0x40] pshufd xmm13, xmm12, 0x0F shufps xmm12, xmm5, 214 pshufd xmm4, xmm12, 0x39 movdqa xmm12, xmm6 shufps xmm12, xmm7, 250 pblendw xmm13, xmm12, 0xCC movdqa xmm12, xmm7 punpcklqdq xmm12, xmm5 pblendw xmm12, xmm6, 0xC0 pshufd xmm12, xmm12, 0x78 punpckhdq xmm5, xmm7 punpckldq xmm6, xmm5 pshufd xmm7, xmm6, 0x1E movdqa xmmword ptr [rsp+0x20], xmm13 movdqa xmmword ptr [rsp+0x40], xmm12 movdqa xmm5, xmmword ptr [rsp+0x30] movdqa xmm13, xmmword ptr [rsp+0x50] pshufd xmm6, xmm5, 0x0F shufps xmm5, xmm13, 214 pshufd xmm12, xmm5, 0x39 movdqa xmm5, xmm14 shufps xmm5, xmm15, 250 pblendw xmm6, xmm5, 0xCC movdqa xmm5, xmm15 punpcklqdq xmm5, xmm13 pblendw xmm5, xmm14, 0xC0 pshufd xmm5, xmm5, 0x78 punpckhdq xmm13, xmm15 punpckldq xmm14, xmm13 pshufd xmm15, xmm14, 0x1E movdqa xmm13, xmm6 movdqa xmm14, xmm5 movdqa xmm5, xmmword ptr [rsp+0x20] movdqa xmm6, xmmword ptr [rsp+0x40] jmp 9b 9: pxor xmm0, xmm2 pxor xmm1, xmm3 pxor xmm8, xmm10 pxor xmm9, xmm11 mov eax, r13d cmp rdx, r15 jne 2b movups xmmword ptr [rbx], xmm0 movups xmmword ptr [rbx+0x10], xmm1 movups xmmword ptr [rbx+0x20], xmm8 movups xmmword ptr [rbx+0x30], xmm9 movdqa xmm0, xmmword ptr [rsp+0x130] movdqa xmm1, xmmword ptr [rsp+0x110] movdqa xmm2, xmmword ptr [rsp+0x120] movdqu xmm3, xmmword ptr [rsp+0x118] movdqu xmm4, xmmword ptr [rsp+0x128] blendvps xmm1, xmm3, xmm0 blendvps xmm2, xmm4, xmm0 movdqa xmmword ptr [rsp+0x110], xmm1 movdqa xmmword ptr [rsp+0x120], xmm2 add rdi, 16 add rbx, 64 sub rsi, 2 3: test esi, 0x1 je 4b movups xmm0, xmmword ptr [rcx] movups xmm1, xmmword ptr [rcx+0x10] movd xmm13, dword ptr [rsp+0x110] pinsrd xmm13, dword ptr [rsp+0x120], 1 pinsrd xmm13, dword ptr [BLAKE3_BLOCK_LEN+rip], 2 movaps xmm14, xmmword ptr [ROT8+rip] movaps xmm15, xmmword ptr [ROT16+rip] mov r8, qword ptr [rdi] movzx eax, byte ptr [rbp+0x40] or eax, r13d xor edx, edx 2: mov r14d, eax or eax, r12d add rdx, 64 cmp rdx, r15 cmovne eax, r14d movaps xmm2, xmmword ptr [BLAKE3_IV+rip] movaps xmm3, xmm13 pinsrd xmm3, eax, 3 movups xmm4, xmmword ptr [r8+rdx-0x40] movups xmm5, xmmword ptr [r8+rdx-0x30] movaps xmm8, xmm4 shufps xmm4, xmm5, 136 shufps xmm8, xmm5, 221 movaps xmm5, xmm8 movups xmm6, xmmword ptr [r8+rdx-0x20] movups xmm7, xmmword ptr [r8+rdx-0x10] movaps xmm8, xmm6 shufps xmm6, xmm7, 136 pshufd xmm6, xmm6, 0x93 shufps xmm8, xmm7, 221 pshufd xmm7, xmm8, 0x93 mov al, 7 9: paddd xmm0, xmm4 paddd xmm0, xmm1 pxor xmm3, xmm0 pshufb xmm3, xmm15 paddd xmm2, xmm3 pxor xmm1, xmm2 movdqa xmm11, xmm1 pslld xmm1, 20 psrld xmm11, 12 por xmm1, xmm11 paddd xmm0, xmm5 paddd xmm0, xmm1 pxor xmm3, xmm0 pshufb xmm3, xmm14 paddd xmm2, xmm3 pxor xmm1, xmm2 movdqa xmm11, xmm1 pslld xmm1, 25 psrld xmm11, 7 por xmm1, xmm11 pshufd xmm0, xmm0, 0x93 pshufd xmm3, xmm3, 0x4E pshufd xmm2, xmm2, 0x39 paddd xmm0, xmm6 paddd xmm0, xmm1 pxor xmm3, xmm0 pshufb xmm3, xmm15 paddd xmm2, xmm3 pxor xmm1, xmm2 movdqa xmm11, xmm1 pslld xmm1, 20 psrld xmm11, 12 por xmm1, xmm11 paddd xmm0, xmm7 paddd xmm0, xmm1 pxor xmm3, xmm0 pshufb xmm3, xmm14 paddd xmm2, xmm3 pxor xmm1, xmm2 movdqa xmm11, xmm1 pslld xmm1, 25 psrld xmm11, 7 por xmm1, xmm11 pshufd xmm0, xmm0, 0x39 pshufd xmm3, xmm3, 0x4E pshufd xmm2, xmm2, 0x93 dec al jz 9f movdqa xmm8, xmm4 shufps xmm8, xmm5, 214 pshufd xmm9, xmm4, 0x0F pshufd xmm4, xmm8, 0x39 movdqa xmm8, xmm6 shufps xmm8, xmm7, 250 pblendw xmm9, xmm8, 0xCC movdqa xmm8, xmm7 punpcklqdq xmm8, xmm5 pblendw xmm8, xmm6, 0xC0 pshufd xmm8, xmm8, 0x78 punpckhdq xmm5, xmm7 punpckldq xmm6, xmm5 pshufd xmm7, xmm6, 0x1E movdqa xmm5, xmm9 movdqa xmm6, xmm8 jmp 9b 9: pxor xmm0, xmm2 pxor xmm1, xmm3 mov eax, r13d cmp rdx, r15 jne 2b movups xmmword ptr [rbx], xmm0 movups xmmword ptr [rbx+0x10], xmm1 jmp 4b .p2align 6 blake3_compress_in_place_sse41: _blake3_compress_in_place_sse41: _CET_ENDBR movups xmm0, xmmword ptr [rdi] movups xmm1, xmmword ptr [rdi+0x10] movaps xmm2, xmmword ptr [BLAKE3_IV+rip] shl r8, 32 add rdx, r8 movq xmm3, rcx movq xmm4, rdx punpcklqdq xmm3, xmm4 movups xmm4, xmmword ptr [rsi] movups xmm5, xmmword ptr [rsi+0x10] movaps xmm8, xmm4 shufps xmm4, xmm5, 136 shufps xmm8, xmm5, 221 movaps xmm5, xmm8 movups xmm6, xmmword ptr [rsi+0x20] movups xmm7, xmmword ptr [rsi+0x30] movaps xmm8, xmm6 shufps xmm6, xmm7, 136 pshufd xmm6, xmm6, 0x93 shufps xmm8, xmm7, 221 pshufd xmm7, xmm8, 0x93 movaps xmm14, xmmword ptr [ROT8+rip] movaps xmm15, xmmword ptr [ROT16+rip] mov al, 7 9: paddd xmm0, xmm4 paddd xmm0, xmm1 pxor xmm3, xmm0 pshufb xmm3, xmm15 paddd xmm2, xmm3 pxor xmm1, xmm2 movdqa xmm11, xmm1 pslld xmm1, 20 psrld xmm11, 12 por xmm1, xmm11 paddd xmm0, xmm5 paddd xmm0, xmm1 pxor xmm3, xmm0 pshufb xmm3, xmm14 paddd xmm2, xmm3 pxor xmm1, xmm2 movdqa xmm11, xmm1 pslld xmm1, 25 psrld xmm11, 7 por xmm1, xmm11 pshufd xmm0, xmm0, 0x93 pshufd xmm3, xmm3, 0x4E pshufd xmm2, xmm2, 0x39 paddd xmm0, xmm6 paddd xmm0, xmm1 pxor xmm3, xmm0 pshufb xmm3, xmm15 paddd xmm2, xmm3 pxor xmm1, xmm2 movdqa xmm11, xmm1 pslld xmm1, 20 psrld xmm11, 12 por xmm1, xmm11 paddd xmm0, xmm7 paddd xmm0, xmm1 pxor xmm3, xmm0 pshufb xmm3, xmm14 paddd xmm2, xmm3 pxor xmm1, xmm2 movdqa xmm11, xmm1 pslld xmm1, 25 psrld xmm11, 7 por xmm1, xmm11 pshufd xmm0, xmm0, 0x39 pshufd xmm3, xmm3, 0x4E pshufd xmm2, xmm2, 0x93 dec al jz 9f movdqa xmm8, xmm4 shufps xmm8, xmm5, 214 pshufd xmm9, xmm4, 0x0F pshufd xmm4, xmm8, 0x39 movdqa xmm8, xmm6 shufps xmm8, xmm7, 250 pblendw xmm9, xmm8, 0xCC movdqa xmm8, xmm7 punpcklqdq xmm8, xmm5 pblendw xmm8, xmm6, 0xC0 pshufd xmm8, xmm8, 0x78 punpckhdq xmm5, xmm7 punpckldq xmm6, xmm5 pshufd xmm7, xmm6, 0x1E movdqa xmm5, xmm9 movdqa xmm6, xmm8 jmp 9b 9: pxor xmm0, xmm2 pxor xmm1, xmm3 movups xmmword ptr [rdi], xmm0 movups xmmword ptr [rdi+0x10], xmm1 ret .p2align 6 blake3_compress_xof_sse41: _blake3_compress_xof_sse41: _CET_ENDBR movups xmm0, xmmword ptr [rdi] movups xmm1, xmmword ptr [rdi+0x10] movaps xmm2, xmmword ptr [BLAKE3_IV+rip] movzx eax, r8b movzx edx, dl shl rax, 32 add rdx, rax movq xmm3, rcx movq xmm4, rdx punpcklqdq xmm3, xmm4 movups xmm4, xmmword ptr [rsi] movups xmm5, xmmword ptr [rsi+0x10] movaps xmm8, xmm4 shufps xmm4, xmm5, 136 shufps xmm8, xmm5, 221 movaps xmm5, xmm8 movups xmm6, xmmword ptr [rsi+0x20] movups xmm7, xmmword ptr [rsi+0x30] movaps xmm8, xmm6 shufps xmm6, xmm7, 136 pshufd xmm6, xmm6, 0x93 shufps xmm8, xmm7, 221 pshufd xmm7, xmm8, 0x93 movaps xmm14, xmmword ptr [ROT8+rip] movaps xmm15, xmmword ptr [ROT16+rip] mov al, 7 9: paddd xmm0, xmm4 paddd xmm0, xmm1 pxor xmm3, xmm0 pshufb xmm3, xmm15 paddd xmm2, xmm3 pxor xmm1, xmm2 movdqa xmm11, xmm1 pslld xmm1, 20 psrld xmm11, 12 por xmm1, xmm11 paddd xmm0, xmm5 paddd xmm0, xmm1 pxor xmm3, xmm0 pshufb xmm3, xmm14 paddd xmm2, xmm3 pxor xmm1, xmm2 movdqa xmm11, xmm1 pslld xmm1, 25 psrld xmm11, 7 por xmm1, xmm11 pshufd xmm0, xmm0, 0x93 pshufd xmm3, xmm3, 0x4E pshufd xmm2, xmm2, 0x39 paddd xmm0, xmm6 paddd xmm0, xmm1 pxor xmm3, xmm0 pshufb xmm3, xmm15 paddd xmm2, xmm3 pxor xmm1, xmm2 movdqa xmm11, xmm1 pslld xmm1, 20 psrld xmm11, 12 por xmm1, xmm11 paddd xmm0, xmm7 paddd xmm0, xmm1 pxor xmm3, xmm0 pshufb xmm3, xmm14 paddd xmm2, xmm3 pxor xmm1, xmm2 movdqa xmm11, xmm1 pslld xmm1, 25 psrld xmm11, 7 por xmm1, xmm11 pshufd xmm0, xmm0, 0x39 pshufd xmm3, xmm3, 0x4E pshufd xmm2, xmm2, 0x93 dec al jz 9f movdqa xmm8, xmm4 shufps xmm8, xmm5, 214 pshufd xmm9, xmm4, 0x0F pshufd xmm4, xmm8, 0x39 movdqa xmm8, xmm6 shufps xmm8, xmm7, 250 pblendw xmm9, xmm8, 0xCC movdqa xmm8, xmm7 punpcklqdq xmm8, xmm5 pblendw xmm8, xmm6, 0xC0 pshufd xmm8, xmm8, 0x78 punpckhdq xmm5, xmm7 punpckldq xmm6, xmm5 pshufd xmm7, xmm6, 0x1E movdqa xmm5, xmm9 movdqa xmm6, xmm8 jmp 9b 9: movdqu xmm4, xmmword ptr [rdi] movdqu xmm5, xmmword ptr [rdi+0x10] pxor xmm0, xmm2 pxor xmm1, xmm3 pxor xmm2, xmm4 pxor xmm3, xmm5 movups xmmword ptr [r9], xmm0 movups xmmword ptr [r9+0x10], xmm1 movups xmmword ptr [r9+0x20], xmm2 movups xmmword ptr [r9+0x30], xmm3 ret #ifdef __APPLE__ .static_data #else .section .rodata #endif .p2align 6 BLAKE3_IV: .long 0x6A09E667, 0xBB67AE85 .long 0x3C6EF372, 0xA54FF53A ROT16: .byte 2, 3, 0, 1, 6, 7, 4, 5, 10, 11, 8, 9, 14, 15, 12, 13 ROT8: .byte 1, 2, 3, 0, 5, 6, 7, 4, 9, 10, 11, 8, 13, 14, 15, 12 ADD0: .long 0, 1, 2, 3 ADD1: .long 4, 4, 4, 4 BLAKE3_IV_0: .long 0x6A09E667, 0x6A09E667, 0x6A09E667, 0x6A09E667 BLAKE3_IV_1: .long 0xBB67AE85, 0xBB67AE85, 0xBB67AE85, 0xBB67AE85 BLAKE3_IV_2: .long 0x3C6EF372, 0x3C6EF372, 0x3C6EF372, 0x3C6EF372 BLAKE3_IV_3: .long 0xA54FF53A, 0xA54FF53A, 0xA54FF53A, 0xA54FF53A BLAKE3_BLOCK_LEN: .long 64, 64, 64, 64 CMP_MSB_MASK: .long 0x80000000, 0x80000000, 0x80000000, 0x80000000 librecast/libs/blake3/c/blake3_sse41_x86-64_windows_gnu.S000066400000000000000000001737431502456746400232610ustar00rootroot00000000000000.intel_syntax noprefix .global blake3_hash_many_sse41 .global _blake3_hash_many_sse41 .global blake3_compress_in_place_sse41 .global _blake3_compress_in_place_sse41 .global blake3_compress_xof_sse41 .global _blake3_compress_xof_sse41 .section .text .p2align 6 _blake3_hash_many_sse41: blake3_hash_many_sse41: push r15 push r14 push r13 push r12 push rsi push rdi push rbx push rbp mov rbp, rsp sub rsp, 528 and rsp, 0xFFFFFFFFFFFFFFC0 movdqa xmmword ptr [rsp+0x170], xmm6 movdqa xmmword ptr [rsp+0x180], xmm7 movdqa xmmword ptr [rsp+0x190], xmm8 movdqa xmmword ptr [rsp+0x1A0], xmm9 movdqa xmmword ptr [rsp+0x1B0], xmm10 movdqa xmmword ptr [rsp+0x1C0], xmm11 movdqa xmmword ptr [rsp+0x1D0], xmm12 movdqa xmmword ptr [rsp+0x1E0], xmm13 movdqa xmmword ptr [rsp+0x1F0], xmm14 movdqa xmmword ptr [rsp+0x200], xmm15 mov rdi, rcx mov rsi, rdx mov rdx, r8 mov rcx, r9 mov r8, qword ptr [rbp+0x68] movzx r9, byte ptr [rbp+0x70] neg r9d movd xmm0, r9d pshufd xmm0, xmm0, 0x00 movdqa xmmword ptr [rsp+0x130], xmm0 movdqa xmm1, xmm0 pand xmm1, xmmword ptr [ADD0+rip] pand xmm0, xmmword ptr [ADD1+rip] movdqa xmmword ptr [rsp+0x150], xmm0 movd xmm0, r8d pshufd xmm0, xmm0, 0x00 paddd xmm0, xmm1 movdqa xmmword ptr [rsp+0x110], xmm0 pxor xmm0, xmmword ptr [CMP_MSB_MASK+rip] pxor xmm1, xmmword ptr [CMP_MSB_MASK+rip] pcmpgtd xmm1, xmm0 shr r8, 32 movd xmm2, r8d pshufd xmm2, xmm2, 0x00 psubd xmm2, xmm1 movdqa xmmword ptr [rsp+0x120], xmm2 mov rbx, qword ptr [rbp+0x90] mov r15, rdx shl r15, 6 movzx r13d, byte ptr [rbp+0x78] movzx r12d, byte ptr [rbp+0x88] cmp rsi, 4 jc 3f 2: movdqu xmm3, xmmword ptr [rcx] pshufd xmm0, xmm3, 0x00 pshufd xmm1, xmm3, 0x55 pshufd xmm2, xmm3, 0xAA pshufd xmm3, xmm3, 0xFF movdqu xmm7, xmmword ptr [rcx+0x10] pshufd xmm4, xmm7, 0x00 pshufd xmm5, xmm7, 0x55 pshufd xmm6, xmm7, 0xAA pshufd xmm7, xmm7, 0xFF mov r8, qword ptr [rdi] mov r9, qword ptr [rdi+0x8] mov r10, qword ptr [rdi+0x10] mov r11, qword ptr [rdi+0x18] movzx eax, byte ptr [rbp+0x80] or eax, r13d xor edx, edx 9: mov r14d, eax or eax, r12d add rdx, 64 cmp rdx, r15 cmovne eax, r14d movdqu xmm8, xmmword ptr [r8+rdx-0x40] movdqu xmm9, xmmword ptr [r9+rdx-0x40] movdqu xmm10, xmmword ptr [r10+rdx-0x40] movdqu xmm11, xmmword ptr [r11+rdx-0x40] movdqa xmm12, xmm8 punpckldq xmm8, xmm9 punpckhdq xmm12, xmm9 movdqa xmm14, xmm10 punpckldq xmm10, xmm11 punpckhdq xmm14, xmm11 movdqa xmm9, xmm8 punpcklqdq xmm8, xmm10 punpckhqdq xmm9, xmm10 movdqa xmm13, xmm12 punpcklqdq xmm12, xmm14 punpckhqdq xmm13, xmm14 movdqa xmmword ptr [rsp], xmm8 movdqa xmmword ptr [rsp+0x10], xmm9 movdqa xmmword ptr [rsp+0x20], xmm12 movdqa xmmword ptr [rsp+0x30], xmm13 movdqu xmm8, xmmword ptr [r8+rdx-0x30] movdqu xmm9, xmmword ptr [r9+rdx-0x30] movdqu xmm10, xmmword ptr [r10+rdx-0x30] movdqu xmm11, xmmword ptr [r11+rdx-0x30] movdqa xmm12, xmm8 punpckldq xmm8, xmm9 punpckhdq xmm12, xmm9 movdqa xmm14, xmm10 punpckldq xmm10, xmm11 punpckhdq xmm14, xmm11 movdqa xmm9, xmm8 punpcklqdq xmm8, xmm10 punpckhqdq xmm9, xmm10 movdqa xmm13, xmm12 punpcklqdq xmm12, xmm14 punpckhqdq xmm13, xmm14 movdqa xmmword ptr [rsp+0x40], xmm8 movdqa xmmword ptr [rsp+0x50], xmm9 movdqa xmmword ptr [rsp+0x60], xmm12 movdqa xmmword ptr [rsp+0x70], xmm13 movdqu xmm8, xmmword ptr [r8+rdx-0x20] movdqu xmm9, xmmword ptr [r9+rdx-0x20] movdqu xmm10, xmmword ptr [r10+rdx-0x20] movdqu xmm11, xmmword ptr [r11+rdx-0x20] movdqa xmm12, xmm8 punpckldq xmm8, xmm9 punpckhdq xmm12, xmm9 movdqa xmm14, xmm10 punpckldq xmm10, xmm11 punpckhdq xmm14, xmm11 movdqa xmm9, xmm8 punpcklqdq xmm8, xmm10 punpckhqdq xmm9, xmm10 movdqa xmm13, xmm12 punpcklqdq xmm12, xmm14 punpckhqdq xmm13, xmm14 movdqa xmmword ptr [rsp+0x80], xmm8 movdqa xmmword ptr [rsp+0x90], xmm9 movdqa xmmword ptr [rsp+0xA0], xmm12 movdqa xmmword ptr [rsp+0xB0], xmm13 movdqu xmm8, xmmword ptr [r8+rdx-0x10] movdqu xmm9, xmmword ptr [r9+rdx-0x10] movdqu xmm10, xmmword ptr [r10+rdx-0x10] movdqu xmm11, xmmword ptr [r11+rdx-0x10] movdqa xmm12, xmm8 punpckldq xmm8, xmm9 punpckhdq xmm12, xmm9 movdqa xmm14, xmm10 punpckldq xmm10, xmm11 punpckhdq xmm14, xmm11 movdqa xmm9, xmm8 punpcklqdq xmm8, xmm10 punpckhqdq xmm9, xmm10 movdqa xmm13, xmm12 punpcklqdq xmm12, xmm14 punpckhqdq xmm13, xmm14 movdqa xmmword ptr [rsp+0xC0], xmm8 movdqa xmmword ptr [rsp+0xD0], xmm9 movdqa xmmword ptr [rsp+0xE0], xmm12 movdqa xmmword ptr [rsp+0xF0], xmm13 movdqa xmm9, xmmword ptr [BLAKE3_IV_1+rip] movdqa xmm10, xmmword ptr [BLAKE3_IV_2+rip] movdqa xmm11, xmmword ptr [BLAKE3_IV_3+rip] movdqa xmm12, xmmword ptr [rsp+0x110] movdqa xmm13, xmmword ptr [rsp+0x120] movdqa xmm14, xmmword ptr [BLAKE3_BLOCK_LEN+rip] movd xmm15, eax pshufd xmm15, xmm15, 0x00 prefetcht0 [r8+rdx+0x80] prefetcht0 [r9+rdx+0x80] prefetcht0 [r10+rdx+0x80] prefetcht0 [r11+rdx+0x80] paddd xmm0, xmmword ptr [rsp] paddd xmm1, xmmword ptr [rsp+0x20] paddd xmm2, xmmword ptr [rsp+0x40] paddd xmm3, xmmword ptr [rsp+0x60] paddd xmm0, xmm4 paddd xmm1, xmm5 paddd xmm2, xmm6 paddd xmm3, xmm7 pxor xmm12, xmm0 pxor xmm13, xmm1 pxor xmm14, xmm2 pxor xmm15, xmm3 movdqa xmm8, xmmword ptr [ROT16+rip] pshufb xmm12, xmm8 pshufb xmm13, xmm8 pshufb xmm14, xmm8 pshufb xmm15, xmm8 movdqa xmm8, xmmword ptr [BLAKE3_IV_0+rip] paddd xmm8, xmm12 paddd xmm9, xmm13 paddd xmm10, xmm14 paddd xmm11, xmm15 pxor xmm4, xmm8 pxor xmm5, xmm9 pxor xmm6, xmm10 pxor xmm7, xmm11 movdqa xmmword ptr [rsp+0x100], xmm8 movdqa xmm8, xmm4 psrld xmm8, 12 pslld xmm4, 20 por xmm4, xmm8 movdqa xmm8, xmm5 psrld xmm8, 12 pslld xmm5, 20 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 12 pslld xmm6, 20 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 12 pslld xmm7, 20 por xmm7, xmm8 paddd xmm0, xmmword ptr [rsp+0x10] paddd xmm1, xmmword ptr [rsp+0x30] paddd xmm2, xmmword ptr [rsp+0x50] paddd xmm3, xmmword ptr [rsp+0x70] paddd xmm0, xmm4 paddd xmm1, xmm5 paddd xmm2, xmm6 paddd xmm3, xmm7 pxor xmm12, xmm0 pxor xmm13, xmm1 pxor xmm14, xmm2 pxor xmm15, xmm3 movdqa xmm8, xmmword ptr [ROT8+rip] pshufb xmm12, xmm8 pshufb xmm13, xmm8 pshufb xmm14, xmm8 pshufb xmm15, xmm8 movdqa xmm8, xmmword ptr [rsp+0x100] paddd xmm8, xmm12 paddd xmm9, xmm13 paddd xmm10, xmm14 paddd xmm11, xmm15 pxor xmm4, xmm8 pxor xmm5, xmm9 pxor xmm6, xmm10 pxor xmm7, xmm11 movdqa xmmword ptr [rsp+0x100], xmm8 movdqa xmm8, xmm4 psrld xmm8, 7 pslld xmm4, 25 por xmm4, xmm8 movdqa xmm8, xmm5 psrld xmm8, 7 pslld xmm5, 25 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 7 pslld xmm6, 25 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 7 pslld xmm7, 25 por xmm7, xmm8 paddd xmm0, xmmword ptr [rsp+0x80] paddd xmm1, xmmword ptr [rsp+0xA0] paddd xmm2, xmmword ptr [rsp+0xC0] paddd xmm3, xmmword ptr [rsp+0xE0] paddd xmm0, xmm5 paddd xmm1, xmm6 paddd xmm2, xmm7 paddd xmm3, xmm4 pxor xmm15, xmm0 pxor xmm12, xmm1 pxor xmm13, xmm2 pxor xmm14, xmm3 movdqa xmm8, xmmword ptr [ROT16+rip] pshufb xmm15, xmm8 pshufb xmm12, xmm8 pshufb xmm13, xmm8 pshufb xmm14, xmm8 paddd xmm10, xmm15 paddd xmm11, xmm12 movdqa xmm8, xmmword ptr [rsp+0x100] paddd xmm8, xmm13 paddd xmm9, xmm14 pxor xmm5, xmm10 pxor xmm6, xmm11 pxor xmm7, xmm8 pxor xmm4, xmm9 movdqa xmmword ptr [rsp+0x100], xmm8 movdqa xmm8, xmm5 psrld xmm8, 12 pslld xmm5, 20 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 12 pslld xmm6, 20 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 12 pslld xmm7, 20 por xmm7, xmm8 movdqa xmm8, xmm4 psrld xmm8, 12 pslld xmm4, 20 por xmm4, xmm8 paddd xmm0, xmmword ptr [rsp+0x90] paddd xmm1, xmmword ptr [rsp+0xB0] paddd xmm2, xmmword ptr [rsp+0xD0] paddd xmm3, xmmword ptr [rsp+0xF0] paddd xmm0, xmm5 paddd xmm1, xmm6 paddd xmm2, xmm7 paddd xmm3, xmm4 pxor xmm15, xmm0 pxor xmm12, xmm1 pxor xmm13, xmm2 pxor xmm14, xmm3 movdqa xmm8, xmmword ptr [ROT8+rip] pshufb xmm15, xmm8 pshufb xmm12, xmm8 pshufb xmm13, xmm8 pshufb xmm14, xmm8 paddd xmm10, xmm15 paddd xmm11, xmm12 movdqa xmm8, xmmword ptr [rsp+0x100] paddd xmm8, xmm13 paddd xmm9, xmm14 pxor xmm5, xmm10 pxor xmm6, xmm11 pxor xmm7, xmm8 pxor xmm4, xmm9 movdqa xmmword ptr [rsp+0x100], xmm8 movdqa xmm8, xmm5 psrld xmm8, 7 pslld xmm5, 25 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 7 pslld xmm6, 25 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 7 pslld xmm7, 25 por xmm7, xmm8 movdqa xmm8, xmm4 psrld xmm8, 7 pslld xmm4, 25 por xmm4, xmm8 paddd xmm0, xmmword ptr [rsp+0x20] paddd xmm1, xmmword ptr [rsp+0x30] paddd xmm2, xmmword ptr [rsp+0x70] paddd xmm3, xmmword ptr [rsp+0x40] paddd xmm0, xmm4 paddd xmm1, xmm5 paddd xmm2, xmm6 paddd xmm3, xmm7 pxor xmm12, xmm0 pxor xmm13, xmm1 pxor xmm14, xmm2 pxor xmm15, xmm3 movdqa xmm8, xmmword ptr [ROT16+rip] pshufb xmm12, xmm8 pshufb xmm13, xmm8 pshufb xmm14, xmm8 pshufb xmm15, xmm8 movdqa xmm8, xmmword ptr [rsp+0x100] paddd xmm8, xmm12 paddd xmm9, xmm13 paddd xmm10, xmm14 paddd xmm11, xmm15 pxor xmm4, xmm8 pxor xmm5, xmm9 pxor xmm6, xmm10 pxor xmm7, xmm11 movdqa xmmword ptr [rsp+0x100], xmm8 movdqa xmm8, xmm4 psrld xmm8, 12 pslld xmm4, 20 por xmm4, xmm8 movdqa xmm8, xmm5 psrld xmm8, 12 pslld xmm5, 20 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 12 pslld xmm6, 20 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 12 pslld xmm7, 20 por xmm7, xmm8 paddd xmm0, xmmword ptr [rsp+0x60] paddd xmm1, xmmword ptr [rsp+0xA0] paddd xmm2, xmmword ptr [rsp] paddd xmm3, xmmword ptr [rsp+0xD0] paddd xmm0, xmm4 paddd xmm1, xmm5 paddd xmm2, xmm6 paddd xmm3, xmm7 pxor xmm12, xmm0 pxor xmm13, xmm1 pxor xmm14, xmm2 pxor xmm15, xmm3 movdqa xmm8, xmmword ptr [ROT8+rip] pshufb xmm12, xmm8 pshufb xmm13, xmm8 pshufb xmm14, xmm8 pshufb xmm15, xmm8 movdqa xmm8, xmmword ptr [rsp+0x100] paddd xmm8, xmm12 paddd xmm9, xmm13 paddd xmm10, xmm14 paddd xmm11, xmm15 pxor xmm4, xmm8 pxor xmm5, xmm9 pxor xmm6, xmm10 pxor xmm7, xmm11 movdqa xmmword ptr [rsp+0x100], xmm8 movdqa xmm8, xmm4 psrld xmm8, 7 pslld xmm4, 25 por xmm4, xmm8 movdqa xmm8, xmm5 psrld xmm8, 7 pslld xmm5, 25 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 7 pslld xmm6, 25 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 7 pslld xmm7, 25 por xmm7, xmm8 paddd xmm0, xmmword ptr [rsp+0x10] paddd xmm1, xmmword ptr [rsp+0xC0] paddd xmm2, xmmword ptr [rsp+0x90] paddd xmm3, xmmword ptr [rsp+0xF0] paddd xmm0, xmm5 paddd xmm1, xmm6 paddd xmm2, xmm7 paddd xmm3, xmm4 pxor xmm15, xmm0 pxor xmm12, xmm1 pxor xmm13, xmm2 pxor xmm14, xmm3 movdqa xmm8, xmmword ptr [ROT16+rip] pshufb xmm15, xmm8 pshufb xmm12, xmm8 pshufb xmm13, xmm8 pshufb xmm14, xmm8 paddd xmm10, xmm15 paddd xmm11, xmm12 movdqa xmm8, xmmword ptr [rsp+0x100] paddd xmm8, xmm13 paddd xmm9, xmm14 pxor xmm5, xmm10 pxor xmm6, xmm11 pxor xmm7, xmm8 pxor xmm4, xmm9 movdqa xmmword ptr [rsp+0x100], xmm8 movdqa xmm8, xmm5 psrld xmm8, 12 pslld xmm5, 20 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 12 pslld xmm6, 20 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 12 pslld xmm7, 20 por xmm7, xmm8 movdqa xmm8, xmm4 psrld xmm8, 12 pslld xmm4, 20 por xmm4, xmm8 paddd xmm0, xmmword ptr [rsp+0xB0] paddd xmm1, xmmword ptr [rsp+0x50] paddd xmm2, xmmword ptr [rsp+0xE0] paddd xmm3, xmmword ptr [rsp+0x80] paddd xmm0, xmm5 paddd xmm1, xmm6 paddd xmm2, xmm7 paddd xmm3, xmm4 pxor xmm15, xmm0 pxor xmm12, xmm1 pxor xmm13, xmm2 pxor xmm14, xmm3 movdqa xmm8, xmmword ptr [ROT8+rip] pshufb xmm15, xmm8 pshufb xmm12, xmm8 pshufb xmm13, xmm8 pshufb xmm14, xmm8 paddd xmm10, xmm15 paddd xmm11, xmm12 movdqa xmm8, xmmword ptr [rsp+0x100] paddd xmm8, xmm13 paddd xmm9, xmm14 pxor xmm5, xmm10 pxor xmm6, xmm11 pxor xmm7, xmm8 pxor xmm4, xmm9 movdqa xmmword ptr [rsp+0x100], xmm8 movdqa xmm8, xmm5 psrld xmm8, 7 pslld xmm5, 25 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 7 pslld xmm6, 25 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 7 pslld xmm7, 25 por xmm7, xmm8 movdqa xmm8, xmm4 psrld xmm8, 7 pslld xmm4, 25 por xmm4, xmm8 paddd xmm0, xmmword ptr [rsp+0x30] paddd xmm1, xmmword ptr [rsp+0xA0] paddd xmm2, xmmword ptr [rsp+0xD0] paddd xmm3, xmmword ptr [rsp+0x70] paddd xmm0, xmm4 paddd xmm1, xmm5 paddd xmm2, xmm6 paddd xmm3, xmm7 pxor xmm12, xmm0 pxor xmm13, xmm1 pxor xmm14, xmm2 pxor xmm15, xmm3 movdqa xmm8, xmmword ptr [ROT16+rip] pshufb xmm12, xmm8 pshufb xmm13, xmm8 pshufb xmm14, xmm8 pshufb xmm15, xmm8 movdqa xmm8, xmmword ptr [rsp+0x100] paddd xmm8, xmm12 paddd xmm9, xmm13 paddd xmm10, xmm14 paddd xmm11, xmm15 pxor xmm4, xmm8 pxor xmm5, xmm9 pxor xmm6, xmm10 pxor xmm7, xmm11 movdqa xmmword ptr [rsp+0x100], xmm8 movdqa xmm8, xmm4 psrld xmm8, 12 pslld xmm4, 20 por xmm4, xmm8 movdqa xmm8, xmm5 psrld xmm8, 12 pslld xmm5, 20 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 12 pslld xmm6, 20 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 12 pslld xmm7, 20 por xmm7, xmm8 paddd xmm0, xmmword ptr [rsp+0x40] paddd xmm1, xmmword ptr [rsp+0xC0] paddd xmm2, xmmword ptr [rsp+0x20] paddd xmm3, xmmword ptr [rsp+0xE0] paddd xmm0, xmm4 paddd xmm1, xmm5 paddd xmm2, xmm6 paddd xmm3, xmm7 pxor xmm12, xmm0 pxor xmm13, xmm1 pxor xmm14, xmm2 pxor xmm15, xmm3 movdqa xmm8, xmmword ptr [ROT8+rip] pshufb xmm12, xmm8 pshufb xmm13, xmm8 pshufb xmm14, xmm8 pshufb xmm15, xmm8 movdqa xmm8, xmmword ptr [rsp+0x100] paddd xmm8, xmm12 paddd xmm9, xmm13 paddd xmm10, xmm14 paddd xmm11, xmm15 pxor xmm4, xmm8 pxor xmm5, xmm9 pxor xmm6, xmm10 pxor xmm7, xmm11 movdqa xmmword ptr [rsp+0x100], xmm8 movdqa xmm8, xmm4 psrld xmm8, 7 pslld xmm4, 25 por xmm4, xmm8 movdqa xmm8, xmm5 psrld xmm8, 7 pslld xmm5, 25 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 7 pslld xmm6, 25 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 7 pslld xmm7, 25 por xmm7, xmm8 paddd xmm0, xmmword ptr [rsp+0x60] paddd xmm1, xmmword ptr [rsp+0x90] paddd xmm2, xmmword ptr [rsp+0xB0] paddd xmm3, xmmword ptr [rsp+0x80] paddd xmm0, xmm5 paddd xmm1, xmm6 paddd xmm2, xmm7 paddd xmm3, xmm4 pxor xmm15, xmm0 pxor xmm12, xmm1 pxor xmm13, xmm2 pxor xmm14, xmm3 movdqa xmm8, xmmword ptr [ROT16+rip] pshufb xmm15, xmm8 pshufb xmm12, xmm8 pshufb xmm13, xmm8 pshufb xmm14, xmm8 paddd xmm10, xmm15 paddd xmm11, xmm12 movdqa xmm8, xmmword ptr [rsp+0x100] paddd xmm8, xmm13 paddd xmm9, xmm14 pxor xmm5, xmm10 pxor xmm6, xmm11 pxor xmm7, xmm8 pxor xmm4, xmm9 movdqa xmmword ptr [rsp+0x100], xmm8 movdqa xmm8, xmm5 psrld xmm8, 12 pslld xmm5, 20 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 12 pslld xmm6, 20 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 12 pslld xmm7, 20 por xmm7, xmm8 movdqa xmm8, xmm4 psrld xmm8, 12 pslld xmm4, 20 por xmm4, xmm8 paddd xmm0, xmmword ptr [rsp+0x50] paddd xmm1, xmmword ptr [rsp] paddd xmm2, xmmword ptr [rsp+0xF0] paddd xmm3, xmmword ptr [rsp+0x10] paddd xmm0, xmm5 paddd xmm1, xmm6 paddd xmm2, xmm7 paddd xmm3, xmm4 pxor xmm15, xmm0 pxor xmm12, xmm1 pxor xmm13, xmm2 pxor xmm14, xmm3 movdqa xmm8, xmmword ptr [ROT8+rip] pshufb xmm15, xmm8 pshufb xmm12, xmm8 pshufb xmm13, xmm8 pshufb xmm14, xmm8 paddd xmm10, xmm15 paddd xmm11, xmm12 movdqa xmm8, xmmword ptr [rsp+0x100] paddd xmm8, xmm13 paddd xmm9, xmm14 pxor xmm5, xmm10 pxor xmm6, xmm11 pxor xmm7, xmm8 pxor xmm4, xmm9 movdqa xmmword ptr [rsp+0x100], xmm8 movdqa xmm8, xmm5 psrld xmm8, 7 pslld xmm5, 25 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 7 pslld xmm6, 25 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 7 pslld xmm7, 25 por xmm7, xmm8 movdqa xmm8, xmm4 psrld xmm8, 7 pslld xmm4, 25 por xmm4, xmm8 paddd xmm0, xmmword ptr [rsp+0xA0] paddd xmm1, xmmword ptr [rsp+0xC0] paddd xmm2, xmmword ptr [rsp+0xE0] paddd xmm3, xmmword ptr [rsp+0xD0] paddd xmm0, xmm4 paddd xmm1, xmm5 paddd xmm2, xmm6 paddd xmm3, xmm7 pxor xmm12, xmm0 pxor xmm13, xmm1 pxor xmm14, xmm2 pxor xmm15, xmm3 movdqa xmm8, xmmword ptr [ROT16+rip] pshufb xmm12, xmm8 pshufb xmm13, xmm8 pshufb xmm14, xmm8 pshufb xmm15, xmm8 movdqa xmm8, xmmword ptr [rsp+0x100] paddd xmm8, xmm12 paddd xmm9, xmm13 paddd xmm10, xmm14 paddd xmm11, xmm15 pxor xmm4, xmm8 pxor xmm5, xmm9 pxor xmm6, xmm10 pxor xmm7, xmm11 movdqa xmmword ptr [rsp+0x100], xmm8 movdqa xmm8, xmm4 psrld xmm8, 12 pslld xmm4, 20 por xmm4, xmm8 movdqa xmm8, xmm5 psrld xmm8, 12 pslld xmm5, 20 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 12 pslld xmm6, 20 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 12 pslld xmm7, 20 por xmm7, xmm8 paddd xmm0, xmmword ptr [rsp+0x70] paddd xmm1, xmmword ptr [rsp+0x90] paddd xmm2, xmmword ptr [rsp+0x30] paddd xmm3, xmmword ptr [rsp+0xF0] paddd xmm0, xmm4 paddd xmm1, xmm5 paddd xmm2, xmm6 paddd xmm3, xmm7 pxor xmm12, xmm0 pxor xmm13, xmm1 pxor xmm14, xmm2 pxor xmm15, xmm3 movdqa xmm8, xmmword ptr [ROT8+rip] pshufb xmm12, xmm8 pshufb xmm13, xmm8 pshufb xmm14, xmm8 pshufb xmm15, xmm8 movdqa xmm8, xmmword ptr [rsp+0x100] paddd xmm8, xmm12 paddd xmm9, xmm13 paddd xmm10, xmm14 paddd xmm11, xmm15 pxor xmm4, xmm8 pxor xmm5, xmm9 pxor xmm6, xmm10 pxor xmm7, xmm11 movdqa xmmword ptr [rsp+0x100], xmm8 movdqa xmm8, xmm4 psrld xmm8, 7 pslld xmm4, 25 por xmm4, xmm8 movdqa xmm8, xmm5 psrld xmm8, 7 pslld xmm5, 25 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 7 pslld xmm6, 25 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 7 pslld xmm7, 25 por xmm7, xmm8 paddd xmm0, xmmword ptr [rsp+0x40] paddd xmm1, xmmword ptr [rsp+0xB0] paddd xmm2, xmmword ptr [rsp+0x50] paddd xmm3, xmmword ptr [rsp+0x10] paddd xmm0, xmm5 paddd xmm1, xmm6 paddd xmm2, xmm7 paddd xmm3, xmm4 pxor xmm15, xmm0 pxor xmm12, xmm1 pxor xmm13, xmm2 pxor xmm14, xmm3 movdqa xmm8, xmmword ptr [ROT16+rip] pshufb xmm15, xmm8 pshufb xmm12, xmm8 pshufb xmm13, xmm8 pshufb xmm14, xmm8 paddd xmm10, xmm15 paddd xmm11, xmm12 movdqa xmm8, xmmword ptr [rsp+0x100] paddd xmm8, xmm13 paddd xmm9, xmm14 pxor xmm5, xmm10 pxor xmm6, xmm11 pxor xmm7, xmm8 pxor xmm4, xmm9 movdqa xmmword ptr [rsp+0x100], xmm8 movdqa xmm8, xmm5 psrld xmm8, 12 pslld xmm5, 20 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 12 pslld xmm6, 20 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 12 pslld xmm7, 20 por xmm7, xmm8 movdqa xmm8, xmm4 psrld xmm8, 12 pslld xmm4, 20 por xmm4, xmm8 paddd xmm0, xmmword ptr [rsp] paddd xmm1, xmmword ptr [rsp+0x20] paddd xmm2, xmmword ptr [rsp+0x80] paddd xmm3, xmmword ptr [rsp+0x60] paddd xmm0, xmm5 paddd xmm1, xmm6 paddd xmm2, xmm7 paddd xmm3, xmm4 pxor xmm15, xmm0 pxor xmm12, xmm1 pxor xmm13, xmm2 pxor xmm14, xmm3 movdqa xmm8, xmmword ptr [ROT8+rip] pshufb xmm15, xmm8 pshufb xmm12, xmm8 pshufb xmm13, xmm8 pshufb xmm14, xmm8 paddd xmm10, xmm15 paddd xmm11, xmm12 movdqa xmm8, xmmword ptr [rsp+0x100] paddd xmm8, xmm13 paddd xmm9, xmm14 pxor xmm5, xmm10 pxor xmm6, xmm11 pxor xmm7, xmm8 pxor xmm4, xmm9 movdqa xmmword ptr [rsp+0x100], xmm8 movdqa xmm8, xmm5 psrld xmm8, 7 pslld xmm5, 25 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 7 pslld xmm6, 25 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 7 pslld xmm7, 25 por xmm7, xmm8 movdqa xmm8, xmm4 psrld xmm8, 7 pslld xmm4, 25 por xmm4, xmm8 paddd xmm0, xmmword ptr [rsp+0xC0] paddd xmm1, xmmword ptr [rsp+0x90] paddd xmm2, xmmword ptr [rsp+0xF0] paddd xmm3, xmmword ptr [rsp+0xE0] paddd xmm0, xmm4 paddd xmm1, xmm5 paddd xmm2, xmm6 paddd xmm3, xmm7 pxor xmm12, xmm0 pxor xmm13, xmm1 pxor xmm14, xmm2 pxor xmm15, xmm3 movdqa xmm8, xmmword ptr [ROT16+rip] pshufb xmm12, xmm8 pshufb xmm13, xmm8 pshufb xmm14, xmm8 pshufb xmm15, xmm8 movdqa xmm8, xmmword ptr [rsp+0x100] paddd xmm8, xmm12 paddd xmm9, xmm13 paddd xmm10, xmm14 paddd xmm11, xmm15 pxor xmm4, xmm8 pxor xmm5, xmm9 pxor xmm6, xmm10 pxor xmm7, xmm11 movdqa xmmword ptr [rsp+0x100], xmm8 movdqa xmm8, xmm4 psrld xmm8, 12 pslld xmm4, 20 por xmm4, xmm8 movdqa xmm8, xmm5 psrld xmm8, 12 pslld xmm5, 20 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 12 pslld xmm6, 20 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 12 pslld xmm7, 20 por xmm7, xmm8 paddd xmm0, xmmword ptr [rsp+0xD0] paddd xmm1, xmmword ptr [rsp+0xB0] paddd xmm2, xmmword ptr [rsp+0xA0] paddd xmm3, xmmword ptr [rsp+0x80] paddd xmm0, xmm4 paddd xmm1, xmm5 paddd xmm2, xmm6 paddd xmm3, xmm7 pxor xmm12, xmm0 pxor xmm13, xmm1 pxor xmm14, xmm2 pxor xmm15, xmm3 movdqa xmm8, xmmword ptr [ROT8+rip] pshufb xmm12, xmm8 pshufb xmm13, xmm8 pshufb xmm14, xmm8 pshufb xmm15, xmm8 movdqa xmm8, xmmword ptr [rsp+0x100] paddd xmm8, xmm12 paddd xmm9, xmm13 paddd xmm10, xmm14 paddd xmm11, xmm15 pxor xmm4, xmm8 pxor xmm5, xmm9 pxor xmm6, xmm10 pxor xmm7, xmm11 movdqa xmmword ptr [rsp+0x100], xmm8 movdqa xmm8, xmm4 psrld xmm8, 7 pslld xmm4, 25 por xmm4, xmm8 movdqa xmm8, xmm5 psrld xmm8, 7 pslld xmm5, 25 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 7 pslld xmm6, 25 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 7 pslld xmm7, 25 por xmm7, xmm8 paddd xmm0, xmmword ptr [rsp+0x70] paddd xmm1, xmmword ptr [rsp+0x50] paddd xmm2, xmmword ptr [rsp] paddd xmm3, xmmword ptr [rsp+0x60] paddd xmm0, xmm5 paddd xmm1, xmm6 paddd xmm2, xmm7 paddd xmm3, xmm4 pxor xmm15, xmm0 pxor xmm12, xmm1 pxor xmm13, xmm2 pxor xmm14, xmm3 movdqa xmm8, xmmword ptr [ROT16+rip] pshufb xmm15, xmm8 pshufb xmm12, xmm8 pshufb xmm13, xmm8 pshufb xmm14, xmm8 paddd xmm10, xmm15 paddd xmm11, xmm12 movdqa xmm8, xmmword ptr [rsp+0x100] paddd xmm8, xmm13 paddd xmm9, xmm14 pxor xmm5, xmm10 pxor xmm6, xmm11 pxor xmm7, xmm8 pxor xmm4, xmm9 movdqa xmmword ptr [rsp+0x100], xmm8 movdqa xmm8, xmm5 psrld xmm8, 12 pslld xmm5, 20 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 12 pslld xmm6, 20 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 12 pslld xmm7, 20 por xmm7, xmm8 movdqa xmm8, xmm4 psrld xmm8, 12 pslld xmm4, 20 por xmm4, xmm8 paddd xmm0, xmmword ptr [rsp+0x20] paddd xmm1, xmmword ptr [rsp+0x30] paddd xmm2, xmmword ptr [rsp+0x10] paddd xmm3, xmmword ptr [rsp+0x40] paddd xmm0, xmm5 paddd xmm1, xmm6 paddd xmm2, xmm7 paddd xmm3, xmm4 pxor xmm15, xmm0 pxor xmm12, xmm1 pxor xmm13, xmm2 pxor xmm14, xmm3 movdqa xmm8, xmmword ptr [ROT8+rip] pshufb xmm15, xmm8 pshufb xmm12, xmm8 pshufb xmm13, xmm8 pshufb xmm14, xmm8 paddd xmm10, xmm15 paddd xmm11, xmm12 movdqa xmm8, xmmword ptr [rsp+0x100] paddd xmm8, xmm13 paddd xmm9, xmm14 pxor xmm5, xmm10 pxor xmm6, xmm11 pxor xmm7, xmm8 pxor xmm4, xmm9 movdqa xmmword ptr [rsp+0x100], xmm8 movdqa xmm8, xmm5 psrld xmm8, 7 pslld xmm5, 25 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 7 pslld xmm6, 25 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 7 pslld xmm7, 25 por xmm7, xmm8 movdqa xmm8, xmm4 psrld xmm8, 7 pslld xmm4, 25 por xmm4, xmm8 paddd xmm0, xmmword ptr [rsp+0x90] paddd xmm1, xmmword ptr [rsp+0xB0] paddd xmm2, xmmword ptr [rsp+0x80] paddd xmm3, xmmword ptr [rsp+0xF0] paddd xmm0, xmm4 paddd xmm1, xmm5 paddd xmm2, xmm6 paddd xmm3, xmm7 pxor xmm12, xmm0 pxor xmm13, xmm1 pxor xmm14, xmm2 pxor xmm15, xmm3 movdqa xmm8, xmmword ptr [ROT16+rip] pshufb xmm12, xmm8 pshufb xmm13, xmm8 pshufb xmm14, xmm8 pshufb xmm15, xmm8 movdqa xmm8, xmmword ptr [rsp+0x100] paddd xmm8, xmm12 paddd xmm9, xmm13 paddd xmm10, xmm14 paddd xmm11, xmm15 pxor xmm4, xmm8 pxor xmm5, xmm9 pxor xmm6, xmm10 pxor xmm7, xmm11 movdqa xmmword ptr [rsp+0x100], xmm8 movdqa xmm8, xmm4 psrld xmm8, 12 pslld xmm4, 20 por xmm4, xmm8 movdqa xmm8, xmm5 psrld xmm8, 12 pslld xmm5, 20 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 12 pslld xmm6, 20 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 12 pslld xmm7, 20 por xmm7, xmm8 paddd xmm0, xmmword ptr [rsp+0xE0] paddd xmm1, xmmword ptr [rsp+0x50] paddd xmm2, xmmword ptr [rsp+0xC0] paddd xmm3, xmmword ptr [rsp+0x10] paddd xmm0, xmm4 paddd xmm1, xmm5 paddd xmm2, xmm6 paddd xmm3, xmm7 pxor xmm12, xmm0 pxor xmm13, xmm1 pxor xmm14, xmm2 pxor xmm15, xmm3 movdqa xmm8, xmmword ptr [ROT8+rip] pshufb xmm12, xmm8 pshufb xmm13, xmm8 pshufb xmm14, xmm8 pshufb xmm15, xmm8 movdqa xmm8, xmmword ptr [rsp+0x100] paddd xmm8, xmm12 paddd xmm9, xmm13 paddd xmm10, xmm14 paddd xmm11, xmm15 pxor xmm4, xmm8 pxor xmm5, xmm9 pxor xmm6, xmm10 pxor xmm7, xmm11 movdqa xmmword ptr [rsp+0x100], xmm8 movdqa xmm8, xmm4 psrld xmm8, 7 pslld xmm4, 25 por xmm4, xmm8 movdqa xmm8, xmm5 psrld xmm8, 7 pslld xmm5, 25 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 7 pslld xmm6, 25 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 7 pslld xmm7, 25 por xmm7, xmm8 paddd xmm0, xmmword ptr [rsp+0xD0] paddd xmm1, xmmword ptr [rsp] paddd xmm2, xmmword ptr [rsp+0x20] paddd xmm3, xmmword ptr [rsp+0x40] paddd xmm0, xmm5 paddd xmm1, xmm6 paddd xmm2, xmm7 paddd xmm3, xmm4 pxor xmm15, xmm0 pxor xmm12, xmm1 pxor xmm13, xmm2 pxor xmm14, xmm3 movdqa xmm8, xmmword ptr [ROT16+rip] pshufb xmm15, xmm8 pshufb xmm12, xmm8 pshufb xmm13, xmm8 pshufb xmm14, xmm8 paddd xmm10, xmm15 paddd xmm11, xmm12 movdqa xmm8, xmmword ptr [rsp+0x100] paddd xmm8, xmm13 paddd xmm9, xmm14 pxor xmm5, xmm10 pxor xmm6, xmm11 pxor xmm7, xmm8 pxor xmm4, xmm9 movdqa xmmword ptr [rsp+0x100], xmm8 movdqa xmm8, xmm5 psrld xmm8, 12 pslld xmm5, 20 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 12 pslld xmm6, 20 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 12 pslld xmm7, 20 por xmm7, xmm8 movdqa xmm8, xmm4 psrld xmm8, 12 pslld xmm4, 20 por xmm4, xmm8 paddd xmm0, xmmword ptr [rsp+0x30] paddd xmm1, xmmword ptr [rsp+0xA0] paddd xmm2, xmmword ptr [rsp+0x60] paddd xmm3, xmmword ptr [rsp+0x70] paddd xmm0, xmm5 paddd xmm1, xmm6 paddd xmm2, xmm7 paddd xmm3, xmm4 pxor xmm15, xmm0 pxor xmm12, xmm1 pxor xmm13, xmm2 pxor xmm14, xmm3 movdqa xmm8, xmmword ptr [ROT8+rip] pshufb xmm15, xmm8 pshufb xmm12, xmm8 pshufb xmm13, xmm8 pshufb xmm14, xmm8 paddd xmm10, xmm15 paddd xmm11, xmm12 movdqa xmm8, xmmword ptr [rsp+0x100] paddd xmm8, xmm13 paddd xmm9, xmm14 pxor xmm5, xmm10 pxor xmm6, xmm11 pxor xmm7, xmm8 pxor xmm4, xmm9 movdqa xmmword ptr [rsp+0x100], xmm8 movdqa xmm8, xmm5 psrld xmm8, 7 pslld xmm5, 25 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 7 pslld xmm6, 25 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 7 pslld xmm7, 25 por xmm7, xmm8 movdqa xmm8, xmm4 psrld xmm8, 7 pslld xmm4, 25 por xmm4, xmm8 paddd xmm0, xmmword ptr [rsp+0xB0] paddd xmm1, xmmword ptr [rsp+0x50] paddd xmm2, xmmword ptr [rsp+0x10] paddd xmm3, xmmword ptr [rsp+0x80] paddd xmm0, xmm4 paddd xmm1, xmm5 paddd xmm2, xmm6 paddd xmm3, xmm7 pxor xmm12, xmm0 pxor xmm13, xmm1 pxor xmm14, xmm2 pxor xmm15, xmm3 movdqa xmm8, xmmword ptr [ROT16+rip] pshufb xmm12, xmm8 pshufb xmm13, xmm8 pshufb xmm14, xmm8 pshufb xmm15, xmm8 movdqa xmm8, xmmword ptr [rsp+0x100] paddd xmm8, xmm12 paddd xmm9, xmm13 paddd xmm10, xmm14 paddd xmm11, xmm15 pxor xmm4, xmm8 pxor xmm5, xmm9 pxor xmm6, xmm10 pxor xmm7, xmm11 movdqa xmmword ptr [rsp+0x100], xmm8 movdqa xmm8, xmm4 psrld xmm8, 12 pslld xmm4, 20 por xmm4, xmm8 movdqa xmm8, xmm5 psrld xmm8, 12 pslld xmm5, 20 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 12 pslld xmm6, 20 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 12 pslld xmm7, 20 por xmm7, xmm8 paddd xmm0, xmmword ptr [rsp+0xF0] paddd xmm1, xmmword ptr [rsp] paddd xmm2, xmmword ptr [rsp+0x90] paddd xmm3, xmmword ptr [rsp+0x60] paddd xmm0, xmm4 paddd xmm1, xmm5 paddd xmm2, xmm6 paddd xmm3, xmm7 pxor xmm12, xmm0 pxor xmm13, xmm1 pxor xmm14, xmm2 pxor xmm15, xmm3 movdqa xmm8, xmmword ptr [ROT8+rip] pshufb xmm12, xmm8 pshufb xmm13, xmm8 pshufb xmm14, xmm8 pshufb xmm15, xmm8 movdqa xmm8, xmmword ptr [rsp+0x100] paddd xmm8, xmm12 paddd xmm9, xmm13 paddd xmm10, xmm14 paddd xmm11, xmm15 pxor xmm4, xmm8 pxor xmm5, xmm9 pxor xmm6, xmm10 pxor xmm7, xmm11 movdqa xmmword ptr [rsp+0x100], xmm8 movdqa xmm8, xmm4 psrld xmm8, 7 pslld xmm4, 25 por xmm4, xmm8 movdqa xmm8, xmm5 psrld xmm8, 7 pslld xmm5, 25 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 7 pslld xmm6, 25 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 7 pslld xmm7, 25 por xmm7, xmm8 paddd xmm0, xmmword ptr [rsp+0xE0] paddd xmm1, xmmword ptr [rsp+0x20] paddd xmm2, xmmword ptr [rsp+0x30] paddd xmm3, xmmword ptr [rsp+0x70] paddd xmm0, xmm5 paddd xmm1, xmm6 paddd xmm2, xmm7 paddd xmm3, xmm4 pxor xmm15, xmm0 pxor xmm12, xmm1 pxor xmm13, xmm2 pxor xmm14, xmm3 movdqa xmm8, xmmword ptr [ROT16+rip] pshufb xmm15, xmm8 pshufb xmm12, xmm8 pshufb xmm13, xmm8 pshufb xmm14, xmm8 paddd xmm10, xmm15 paddd xmm11, xmm12 movdqa xmm8, xmmword ptr [rsp+0x100] paddd xmm8, xmm13 paddd xmm9, xmm14 pxor xmm5, xmm10 pxor xmm6, xmm11 pxor xmm7, xmm8 pxor xmm4, xmm9 movdqa xmmword ptr [rsp+0x100], xmm8 movdqa xmm8, xmm5 psrld xmm8, 12 pslld xmm5, 20 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 12 pslld xmm6, 20 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 12 pslld xmm7, 20 por xmm7, xmm8 movdqa xmm8, xmm4 psrld xmm8, 12 pslld xmm4, 20 por xmm4, xmm8 paddd xmm0, xmmword ptr [rsp+0xA0] paddd xmm1, xmmword ptr [rsp+0xC0] paddd xmm2, xmmword ptr [rsp+0x40] paddd xmm3, xmmword ptr [rsp+0xD0] paddd xmm0, xmm5 paddd xmm1, xmm6 paddd xmm2, xmm7 paddd xmm3, xmm4 pxor xmm15, xmm0 pxor xmm12, xmm1 pxor xmm13, xmm2 pxor xmm14, xmm3 movdqa xmm8, xmmword ptr [ROT8+rip] pshufb xmm15, xmm8 pshufb xmm12, xmm8 pshufb xmm13, xmm8 pshufb xmm14, xmm8 paddd xmm10, xmm15 paddd xmm11, xmm12 movdqa xmm8, xmmword ptr [rsp+0x100] paddd xmm8, xmm13 paddd xmm9, xmm14 pxor xmm5, xmm10 pxor xmm6, xmm11 pxor xmm7, xmm8 pxor xmm4, xmm9 pxor xmm0, xmm8 pxor xmm1, xmm9 pxor xmm2, xmm10 pxor xmm3, xmm11 movdqa xmm8, xmm5 psrld xmm8, 7 pslld xmm5, 25 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 7 pslld xmm6, 25 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 7 pslld xmm7, 25 por xmm7, xmm8 movdqa xmm8, xmm4 psrld xmm8, 7 pslld xmm4, 25 por xmm4, xmm8 pxor xmm4, xmm12 pxor xmm5, xmm13 pxor xmm6, xmm14 pxor xmm7, xmm15 mov eax, r13d jne 9b movdqa xmm9, xmm0 punpckldq xmm0, xmm1 punpckhdq xmm9, xmm1 movdqa xmm11, xmm2 punpckldq xmm2, xmm3 punpckhdq xmm11, xmm3 movdqa xmm1, xmm0 punpcklqdq xmm0, xmm2 punpckhqdq xmm1, xmm2 movdqa xmm3, xmm9 punpcklqdq xmm9, xmm11 punpckhqdq xmm3, xmm11 movdqu xmmword ptr [rbx], xmm0 movdqu xmmword ptr [rbx+0x20], xmm1 movdqu xmmword ptr [rbx+0x40], xmm9 movdqu xmmword ptr [rbx+0x60], xmm3 movdqa xmm9, xmm4 punpckldq xmm4, xmm5 punpckhdq xmm9, xmm5 movdqa xmm11, xmm6 punpckldq xmm6, xmm7 punpckhdq xmm11, xmm7 movdqa xmm5, xmm4 punpcklqdq xmm4, xmm6 punpckhqdq xmm5, xmm6 movdqa xmm7, xmm9 punpcklqdq xmm9, xmm11 punpckhqdq xmm7, xmm11 movdqu xmmword ptr [rbx+0x10], xmm4 movdqu xmmword ptr [rbx+0x30], xmm5 movdqu xmmword ptr [rbx+0x50], xmm9 movdqu xmmword ptr [rbx+0x70], xmm7 movdqa xmm1, xmmword ptr [rsp+0x110] movdqa xmm0, xmm1 paddd xmm1, xmmword ptr [rsp+0x150] movdqa xmmword ptr [rsp+0x110], xmm1 pxor xmm0, xmmword ptr [CMP_MSB_MASK+rip] pxor xmm1, xmmword ptr [CMP_MSB_MASK+rip] pcmpgtd xmm0, xmm1 movdqa xmm1, xmmword ptr [rsp+0x120] psubd xmm1, xmm0 movdqa xmmword ptr [rsp+0x120], xmm1 add rbx, 128 add rdi, 32 sub rsi, 4 cmp rsi, 4 jnc 2b test rsi, rsi jne 3f 4: movdqa xmm6, xmmword ptr [rsp+0x170] movdqa xmm7, xmmword ptr [rsp+0x180] movdqa xmm8, xmmword ptr [rsp+0x190] movdqa xmm9, xmmword ptr [rsp+0x1A0] movdqa xmm10, xmmword ptr [rsp+0x1B0] movdqa xmm11, xmmword ptr [rsp+0x1C0] movdqa xmm12, xmmword ptr [rsp+0x1D0] movdqa xmm13, xmmword ptr [rsp+0x1E0] movdqa xmm14, xmmword ptr [rsp+0x1F0] movdqa xmm15, xmmword ptr [rsp+0x200] mov rsp, rbp pop rbp pop rbx pop rdi pop rsi pop r12 pop r13 pop r14 pop r15 ret .p2align 5 3: test esi, 0x2 je 3f movups xmm0, xmmword ptr [rcx] movups xmm1, xmmword ptr [rcx+0x10] movaps xmm8, xmm0 movaps xmm9, xmm1 movd xmm13, dword ptr [rsp+0x110] pinsrd xmm13, dword ptr [rsp+0x120], 1 pinsrd xmm13, dword ptr [BLAKE3_BLOCK_LEN+rip], 2 movaps xmmword ptr [rsp], xmm13 movd xmm14, dword ptr [rsp+0x114] pinsrd xmm14, dword ptr [rsp+0x124], 1 pinsrd xmm14, dword ptr [BLAKE3_BLOCK_LEN+rip], 2 movaps xmmword ptr [rsp+0x10], xmm14 mov r8, qword ptr [rdi] mov r9, qword ptr [rdi+0x8] movzx eax, byte ptr [rbp+0x80] or eax, r13d xor edx, edx 2: mov r14d, eax or eax, r12d add rdx, 64 cmp rdx, r15 cmovne eax, r14d movaps xmm2, xmmword ptr [BLAKE3_IV+rip] movaps xmm10, xmm2 movups xmm4, xmmword ptr [r8+rdx-0x40] movups xmm5, xmmword ptr [r8+rdx-0x30] movaps xmm3, xmm4 shufps xmm4, xmm5, 136 shufps xmm3, xmm5, 221 movaps xmm5, xmm3 movups xmm6, xmmword ptr [r8+rdx-0x20] movups xmm7, xmmword ptr [r8+rdx-0x10] movaps xmm3, xmm6 shufps xmm6, xmm7, 136 pshufd xmm6, xmm6, 0x93 shufps xmm3, xmm7, 221 pshufd xmm7, xmm3, 0x93 movups xmm12, xmmword ptr [r9+rdx-0x40] movups xmm13, xmmword ptr [r9+rdx-0x30] movaps xmm11, xmm12 shufps xmm12, xmm13, 136 shufps xmm11, xmm13, 221 movaps xmm13, xmm11 movups xmm14, xmmword ptr [r9+rdx-0x20] movups xmm15, xmmword ptr [r9+rdx-0x10] movaps xmm11, xmm14 shufps xmm14, xmm15, 136 pshufd xmm14, xmm14, 0x93 shufps xmm11, xmm15, 221 pshufd xmm15, xmm11, 0x93 movaps xmm3, xmmword ptr [rsp] movaps xmm11, xmmword ptr [rsp+0x10] pinsrd xmm3, eax, 3 pinsrd xmm11, eax, 3 mov al, 7 9: paddd xmm0, xmm4 paddd xmm8, xmm12 movaps xmmword ptr [rsp+0x20], xmm4 movaps xmmword ptr [rsp+0x30], xmm12 paddd xmm0, xmm1 paddd xmm8, xmm9 pxor xmm3, xmm0 pxor xmm11, xmm8 movaps xmm12, xmmword ptr [ROT16+rip] pshufb xmm3, xmm12 pshufb xmm11, xmm12 paddd xmm2, xmm3 paddd xmm10, xmm11 pxor xmm1, xmm2 pxor xmm9, xmm10 movdqa xmm4, xmm1 pslld xmm1, 20 psrld xmm4, 12 por xmm1, xmm4 movdqa xmm4, xmm9 pslld xmm9, 20 psrld xmm4, 12 por xmm9, xmm4 paddd xmm0, xmm5 paddd xmm8, xmm13 movaps xmmword ptr [rsp+0x40], xmm5 movaps xmmword ptr [rsp+0x50], xmm13 paddd xmm0, xmm1 paddd xmm8, xmm9 pxor xmm3, xmm0 pxor xmm11, xmm8 movaps xmm13, xmmword ptr [ROT8+rip] pshufb xmm3, xmm13 pshufb xmm11, xmm13 paddd xmm2, xmm3 paddd xmm10, xmm11 pxor xmm1, xmm2 pxor xmm9, xmm10 movdqa xmm4, xmm1 pslld xmm1, 25 psrld xmm4, 7 por xmm1, xmm4 movdqa xmm4, xmm9 pslld xmm9, 25 psrld xmm4, 7 por xmm9, xmm4 pshufd xmm0, xmm0, 0x93 pshufd xmm8, xmm8, 0x93 pshufd xmm3, xmm3, 0x4E pshufd xmm11, xmm11, 0x4E pshufd xmm2, xmm2, 0x39 pshufd xmm10, xmm10, 0x39 paddd xmm0, xmm6 paddd xmm8, xmm14 paddd xmm0, xmm1 paddd xmm8, xmm9 pxor xmm3, xmm0 pxor xmm11, xmm8 pshufb xmm3, xmm12 pshufb xmm11, xmm12 paddd xmm2, xmm3 paddd xmm10, xmm11 pxor xmm1, xmm2 pxor xmm9, xmm10 movdqa xmm4, xmm1 pslld xmm1, 20 psrld xmm4, 12 por xmm1, xmm4 movdqa xmm4, xmm9 pslld xmm9, 20 psrld xmm4, 12 por xmm9, xmm4 paddd xmm0, xmm7 paddd xmm8, xmm15 paddd xmm0, xmm1 paddd xmm8, xmm9 pxor xmm3, xmm0 pxor xmm11, xmm8 pshufb xmm3, xmm13 pshufb xmm11, xmm13 paddd xmm2, xmm3 paddd xmm10, xmm11 pxor xmm1, xmm2 pxor xmm9, xmm10 movdqa xmm4, xmm1 pslld xmm1, 25 psrld xmm4, 7 por xmm1, xmm4 movdqa xmm4, xmm9 pslld xmm9, 25 psrld xmm4, 7 por xmm9, xmm4 pshufd xmm0, xmm0, 0x39 pshufd xmm8, xmm8, 0x39 pshufd xmm3, xmm3, 0x4E pshufd xmm11, xmm11, 0x4E pshufd xmm2, xmm2, 0x93 pshufd xmm10, xmm10, 0x93 dec al je 9f movdqa xmm12, xmmword ptr [rsp+0x20] movdqa xmm5, xmmword ptr [rsp+0x40] pshufd xmm13, xmm12, 0x0F shufps xmm12, xmm5, 214 pshufd xmm4, xmm12, 0x39 movdqa xmm12, xmm6 shufps xmm12, xmm7, 250 pblendw xmm13, xmm12, 0xCC movdqa xmm12, xmm7 punpcklqdq xmm12, xmm5 pblendw xmm12, xmm6, 0xC0 pshufd xmm12, xmm12, 0x78 punpckhdq xmm5, xmm7 punpckldq xmm6, xmm5 pshufd xmm7, xmm6, 0x1E movdqa xmmword ptr [rsp+0x20], xmm13 movdqa xmmword ptr [rsp+0x40], xmm12 movdqa xmm5, xmmword ptr [rsp+0x30] movdqa xmm13, xmmword ptr [rsp+0x50] pshufd xmm6, xmm5, 0x0F shufps xmm5, xmm13, 214 pshufd xmm12, xmm5, 0x39 movdqa xmm5, xmm14 shufps xmm5, xmm15, 250 pblendw xmm6, xmm5, 0xCC movdqa xmm5, xmm15 punpcklqdq xmm5, xmm13 pblendw xmm5, xmm14, 0xC0 pshufd xmm5, xmm5, 0x78 punpckhdq xmm13, xmm15 punpckldq xmm14, xmm13 pshufd xmm15, xmm14, 0x1E movdqa xmm13, xmm6 movdqa xmm14, xmm5 movdqa xmm5, xmmword ptr [rsp+0x20] movdqa xmm6, xmmword ptr [rsp+0x40] jmp 9b 9: pxor xmm0, xmm2 pxor xmm1, xmm3 pxor xmm8, xmm10 pxor xmm9, xmm11 mov eax, r13d cmp rdx, r15 jne 2b movups xmmword ptr [rbx], xmm0 movups xmmword ptr [rbx+0x10], xmm1 movups xmmword ptr [rbx+0x20], xmm8 movups xmmword ptr [rbx+0x30], xmm9 movdqa xmm0, xmmword ptr [rsp+0x130] movdqa xmm1, xmmword ptr [rsp+0x110] movdqa xmm2, xmmword ptr [rsp+0x120] movdqu xmm3, xmmword ptr [rsp+0x118] movdqu xmm4, xmmword ptr [rsp+0x128] blendvps xmm1, xmm3, xmm0 blendvps xmm2, xmm4, xmm0 movdqa xmmword ptr [rsp+0x110], xmm1 movdqa xmmword ptr [rsp+0x120], xmm2 add rdi, 16 add rbx, 64 sub rsi, 2 3: test esi, 0x1 je 4b movups xmm0, xmmword ptr [rcx] movups xmm1, xmmword ptr [rcx+0x10] movd xmm13, dword ptr [rsp+0x110] pinsrd xmm13, dword ptr [rsp+0x120], 1 pinsrd xmm13, dword ptr [BLAKE3_BLOCK_LEN+rip], 2 movaps xmm14, xmmword ptr [ROT8+rip] movaps xmm15, xmmword ptr [ROT16+rip] mov r8, qword ptr [rdi] movzx eax, byte ptr [rbp+0x80] or eax, r13d xor edx, edx 2: mov r14d, eax or eax, r12d add rdx, 64 cmp rdx, r15 cmovne eax, r14d movaps xmm2, xmmword ptr [BLAKE3_IV+rip] movaps xmm3, xmm13 pinsrd xmm3, eax, 3 movups xmm4, xmmword ptr [r8+rdx-0x40] movups xmm5, xmmword ptr [r8+rdx-0x30] movaps xmm8, xmm4 shufps xmm4, xmm5, 136 shufps xmm8, xmm5, 221 movaps xmm5, xmm8 movups xmm6, xmmword ptr [r8+rdx-0x20] movups xmm7, xmmword ptr [r8+rdx-0x10] movaps xmm8, xmm6 shufps xmm6, xmm7, 136 pshufd xmm6, xmm6, 0x93 shufps xmm8, xmm7, 221 pshufd xmm7, xmm8, 0x93 mov al, 7 9: paddd xmm0, xmm4 paddd xmm0, xmm1 pxor xmm3, xmm0 pshufb xmm3, xmm15 paddd xmm2, xmm3 pxor xmm1, xmm2 movdqa xmm11, xmm1 pslld xmm1, 20 psrld xmm11, 12 por xmm1, xmm11 paddd xmm0, xmm5 paddd xmm0, xmm1 pxor xmm3, xmm0 pshufb xmm3, xmm14 paddd xmm2, xmm3 pxor xmm1, xmm2 movdqa xmm11, xmm1 pslld xmm1, 25 psrld xmm11, 7 por xmm1, xmm11 pshufd xmm0, xmm0, 0x93 pshufd xmm3, xmm3, 0x4E pshufd xmm2, xmm2, 0x39 paddd xmm0, xmm6 paddd xmm0, xmm1 pxor xmm3, xmm0 pshufb xmm3, xmm15 paddd xmm2, xmm3 pxor xmm1, xmm2 movdqa xmm11, xmm1 pslld xmm1, 20 psrld xmm11, 12 por xmm1, xmm11 paddd xmm0, xmm7 paddd xmm0, xmm1 pxor xmm3, xmm0 pshufb xmm3, xmm14 paddd xmm2, xmm3 pxor xmm1, xmm2 movdqa xmm11, xmm1 pslld xmm1, 25 psrld xmm11, 7 por xmm1, xmm11 pshufd xmm0, xmm0, 0x39 pshufd xmm3, xmm3, 0x4E pshufd xmm2, xmm2, 0x93 dec al jz 9f movdqa xmm8, xmm4 shufps xmm8, xmm5, 214 pshufd xmm9, xmm4, 0x0F pshufd xmm4, xmm8, 0x39 movdqa xmm8, xmm6 shufps xmm8, xmm7, 250 pblendw xmm9, xmm8, 0xCC movdqa xmm8, xmm7 punpcklqdq xmm8, xmm5 pblendw xmm8, xmm6, 0xC0 pshufd xmm8, xmm8, 0x78 punpckhdq xmm5, xmm7 punpckldq xmm6, xmm5 pshufd xmm7, xmm6, 0x1E movdqa xmm5, xmm9 movdqa xmm6, xmm8 jmp 9b 9: pxor xmm0, xmm2 pxor xmm1, xmm3 mov eax, r13d cmp rdx, r15 jne 2b movups xmmword ptr [rbx], xmm0 movups xmmword ptr [rbx+0x10], xmm1 jmp 4b .p2align 6 blake3_compress_in_place_sse41: _blake3_compress_in_place_sse41: sub rsp, 120 movdqa xmmword ptr [rsp], xmm6 movdqa xmmword ptr [rsp+0x10], xmm7 movdqa xmmword ptr [rsp+0x20], xmm8 movdqa xmmword ptr [rsp+0x30], xmm9 movdqa xmmword ptr [rsp+0x40], xmm11 movdqa xmmword ptr [rsp+0x50], xmm14 movdqa xmmword ptr [rsp+0x60], xmm15 movups xmm0, xmmword ptr [rcx] movups xmm1, xmmword ptr [rcx+0x10] movaps xmm2, xmmword ptr [BLAKE3_IV+rip] movzx eax, byte ptr [rsp+0xA0] movzx r8d, r8b shl rax, 32 add r8, rax movq xmm3, r9 movq xmm4, r8 punpcklqdq xmm3, xmm4 movups xmm4, xmmword ptr [rdx] movups xmm5, xmmword ptr [rdx+0x10] movaps xmm8, xmm4 shufps xmm4, xmm5, 136 shufps xmm8, xmm5, 221 movaps xmm5, xmm8 movups xmm6, xmmword ptr [rdx+0x20] movups xmm7, xmmword ptr [rdx+0x30] movaps xmm8, xmm6 shufps xmm6, xmm7, 136 pshufd xmm6, xmm6, 0x93 shufps xmm8, xmm7, 221 pshufd xmm7, xmm8, 0x93 movaps xmm14, xmmword ptr [ROT8+rip] movaps xmm15, xmmword ptr [ROT16+rip] mov al, 7 9: paddd xmm0, xmm4 paddd xmm0, xmm1 pxor xmm3, xmm0 pshufb xmm3, xmm15 paddd xmm2, xmm3 pxor xmm1, xmm2 movdqa xmm11, xmm1 pslld xmm1, 20 psrld xmm11, 12 por xmm1, xmm11 paddd xmm0, xmm5 paddd xmm0, xmm1 pxor xmm3, xmm0 pshufb xmm3, xmm14 paddd xmm2, xmm3 pxor xmm1, xmm2 movdqa xmm11, xmm1 pslld xmm1, 25 psrld xmm11, 7 por xmm1, xmm11 pshufd xmm0, xmm0, 0x93 pshufd xmm3, xmm3, 0x4E pshufd xmm2, xmm2, 0x39 paddd xmm0, xmm6 paddd xmm0, xmm1 pxor xmm3, xmm0 pshufb xmm3, xmm15 paddd xmm2, xmm3 pxor xmm1, xmm2 movdqa xmm11, xmm1 pslld xmm1, 20 psrld xmm11, 12 por xmm1, xmm11 paddd xmm0, xmm7 paddd xmm0, xmm1 pxor xmm3, xmm0 pshufb xmm3, xmm14 paddd xmm2, xmm3 pxor xmm1, xmm2 movdqa xmm11, xmm1 pslld xmm1, 25 psrld xmm11, 7 por xmm1, xmm11 pshufd xmm0, xmm0, 0x39 pshufd xmm3, xmm3, 0x4E pshufd xmm2, xmm2, 0x93 dec al jz 9f movdqa xmm8, xmm4 shufps xmm8, xmm5, 214 pshufd xmm9, xmm4, 0x0F pshufd xmm4, xmm8, 0x39 movdqa xmm8, xmm6 shufps xmm8, xmm7, 250 pblendw xmm9, xmm8, 0xCC movdqa xmm8, xmm7 punpcklqdq xmm8, xmm5 pblendw xmm8, xmm6, 0xC0 pshufd xmm8, xmm8, 0x78 punpckhdq xmm5, xmm7 punpckldq xmm6, xmm5 pshufd xmm7, xmm6, 0x1E movdqa xmm5, xmm9 movdqa xmm6, xmm8 jmp 9b 9: pxor xmm0, xmm2 pxor xmm1, xmm3 movups xmmword ptr [rcx], xmm0 movups xmmword ptr [rcx+0x10], xmm1 movdqa xmm6, xmmword ptr [rsp] movdqa xmm7, xmmword ptr [rsp+0x10] movdqa xmm8, xmmword ptr [rsp+0x20] movdqa xmm9, xmmword ptr [rsp+0x30] movdqa xmm11, xmmword ptr [rsp+0x40] movdqa xmm14, xmmword ptr [rsp+0x50] movdqa xmm15, xmmword ptr [rsp+0x60] add rsp, 120 ret .p2align 6 _blake3_compress_xof_sse41: blake3_compress_xof_sse41: sub rsp, 120 movdqa xmmword ptr [rsp], xmm6 movdqa xmmword ptr [rsp+0x10], xmm7 movdqa xmmword ptr [rsp+0x20], xmm8 movdqa xmmword ptr [rsp+0x30], xmm9 movdqa xmmword ptr [rsp+0x40], xmm11 movdqa xmmword ptr [rsp+0x50], xmm14 movdqa xmmword ptr [rsp+0x60], xmm15 movups xmm0, xmmword ptr [rcx] movups xmm1, xmmword ptr [rcx+0x10] movaps xmm2, xmmword ptr [BLAKE3_IV+rip] movzx eax, byte ptr [rsp+0xA0] movzx r8d, r8b mov r10, qword ptr [rsp+0xA8] shl rax, 32 add r8, rax movq xmm3, r9 movq xmm4, r8 punpcklqdq xmm3, xmm4 movups xmm4, xmmword ptr [rdx] movups xmm5, xmmword ptr [rdx+0x10] movaps xmm8, xmm4 shufps xmm4, xmm5, 136 shufps xmm8, xmm5, 221 movaps xmm5, xmm8 movups xmm6, xmmword ptr [rdx+0x20] movups xmm7, xmmword ptr [rdx+0x30] movaps xmm8, xmm6 shufps xmm6, xmm7, 136 pshufd xmm6, xmm6, 0x93 shufps xmm8, xmm7, 221 pshufd xmm7, xmm8, 0x93 movaps xmm14, xmmword ptr [ROT8+rip] movaps xmm15, xmmword ptr [ROT16+rip] mov al, 7 9: paddd xmm0, xmm4 paddd xmm0, xmm1 pxor xmm3, xmm0 pshufb xmm3, xmm15 paddd xmm2, xmm3 pxor xmm1, xmm2 movdqa xmm11, xmm1 pslld xmm1, 20 psrld xmm11, 12 por xmm1, xmm11 paddd xmm0, xmm5 paddd xmm0, xmm1 pxor xmm3, xmm0 pshufb xmm3, xmm14 paddd xmm2, xmm3 pxor xmm1, xmm2 movdqa xmm11, xmm1 pslld xmm1, 25 psrld xmm11, 7 por xmm1, xmm11 pshufd xmm0, xmm0, 0x93 pshufd xmm3, xmm3, 0x4E pshufd xmm2, xmm2, 0x39 paddd xmm0, xmm6 paddd xmm0, xmm1 pxor xmm3, xmm0 pshufb xmm3, xmm15 paddd xmm2, xmm3 pxor xmm1, xmm2 movdqa xmm11, xmm1 pslld xmm1, 20 psrld xmm11, 12 por xmm1, xmm11 paddd xmm0, xmm7 paddd xmm0, xmm1 pxor xmm3, xmm0 pshufb xmm3, xmm14 paddd xmm2, xmm3 pxor xmm1, xmm2 movdqa xmm11, xmm1 pslld xmm1, 25 psrld xmm11, 7 por xmm1, xmm11 pshufd xmm0, xmm0, 0x39 pshufd xmm3, xmm3, 0x4E pshufd xmm2, xmm2, 0x93 dec al jz 9f movdqa xmm8, xmm4 shufps xmm8, xmm5, 214 pshufd xmm9, xmm4, 0x0F pshufd xmm4, xmm8, 0x39 movdqa xmm8, xmm6 shufps xmm8, xmm7, 250 pblendw xmm9, xmm8, 0xCC movdqa xmm8, xmm7 punpcklqdq xmm8, xmm5 pblendw xmm8, xmm6, 0xC0 pshufd xmm8, xmm8, 0x78 punpckhdq xmm5, xmm7 punpckldq xmm6, xmm5 pshufd xmm7, xmm6, 0x1E movdqa xmm5, xmm9 movdqa xmm6, xmm8 jmp 9b 9: movdqu xmm4, xmmword ptr [rcx] movdqu xmm5, xmmword ptr [rcx+0x10] pxor xmm0, xmm2 pxor xmm1, xmm3 pxor xmm2, xmm4 pxor xmm3, xmm5 movups xmmword ptr [r10], xmm0 movups xmmword ptr [r10+0x10], xmm1 movups xmmword ptr [r10+0x20], xmm2 movups xmmword ptr [r10+0x30], xmm3 movdqa xmm6, xmmword ptr [rsp] movdqa xmm7, xmmword ptr [rsp+0x10] movdqa xmm8, xmmword ptr [rsp+0x20] movdqa xmm9, xmmword ptr [rsp+0x30] movdqa xmm11, xmmword ptr [rsp+0x40] movdqa xmm14, xmmword ptr [rsp+0x50] movdqa xmm15, xmmword ptr [rsp+0x60] add rsp, 120 ret .section .rdata .p2align 6 BLAKE3_IV: .long 0x6A09E667, 0xBB67AE85 .long 0x3C6EF372, 0xA54FF53A ROT16: .byte 2, 3, 0, 1, 6, 7, 4, 5, 10, 11, 8, 9, 14, 15, 12, 13 ROT8: .byte 1, 2, 3, 0, 5, 6, 7, 4, 9, 10, 11, 8, 13, 14, 15, 12 ADD0: .long 0, 1, 2, 3 ADD1: .long 4, 4, 4, 4 BLAKE3_IV_0: .long 0x6A09E667, 0x6A09E667, 0x6A09E667, 0x6A09E667 BLAKE3_IV_1: .long 0xBB67AE85, 0xBB67AE85, 0xBB67AE85, 0xBB67AE85 BLAKE3_IV_2: .long 0x3C6EF372, 0x3C6EF372, 0x3C6EF372, 0x3C6EF372 BLAKE3_IV_3: .long 0xA54FF53A, 0xA54FF53A, 0xA54FF53A, 0xA54FF53A BLAKE3_BLOCK_LEN: .long 64, 64, 64, 64 CMP_MSB_MASK: .long 0x80000000, 0x80000000, 0x80000000, 0x80000000 librecast/libs/blake3/c/blake3_sse41_x86-64_windows_msvc.asm000066400000000000000000001733321502456746400240100ustar00rootroot00000000000000public _blake3_hash_many_sse41 public blake3_hash_many_sse41 public blake3_compress_in_place_sse41 public _blake3_compress_in_place_sse41 public blake3_compress_xof_sse41 public _blake3_compress_xof_sse41 _TEXT SEGMENT ALIGN(16) 'CODE' ALIGN 16 blake3_hash_many_sse41 PROC _blake3_hash_many_sse41 PROC push r15 push r14 push r13 push r12 push rsi push rdi push rbx push rbp mov rbp, rsp sub rsp, 528 and rsp, 0FFFFFFFFFFFFFFC0H movdqa xmmword ptr [rsp+170H], xmm6 movdqa xmmword ptr [rsp+180H], xmm7 movdqa xmmword ptr [rsp+190H], xmm8 movdqa xmmword ptr [rsp+1A0H], xmm9 movdqa xmmword ptr [rsp+1B0H], xmm10 movdqa xmmword ptr [rsp+1C0H], xmm11 movdqa xmmword ptr [rsp+1D0H], xmm12 movdqa xmmword ptr [rsp+1E0H], xmm13 movdqa xmmword ptr [rsp+1F0H], xmm14 movdqa xmmword ptr [rsp+200H], xmm15 mov rdi, rcx mov rsi, rdx mov rdx, r8 mov rcx, r9 mov r8, qword ptr [rbp+68H] movzx r9, byte ptr [rbp+70H] neg r9d movd xmm0, r9d pshufd xmm0, xmm0, 00H movdqa xmmword ptr [rsp+130H], xmm0 movdqa xmm1, xmm0 pand xmm1, xmmword ptr [ADD0] pand xmm0, xmmword ptr [ADD1] movdqa xmmword ptr [rsp+150H], xmm0 movd xmm0, r8d pshufd xmm0, xmm0, 00H paddd xmm0, xmm1 movdqa xmmword ptr [rsp+110H], xmm0 pxor xmm0, xmmword ptr [CMP_MSB_MASK] pxor xmm1, xmmword ptr [CMP_MSB_MASK] pcmpgtd xmm1, xmm0 shr r8, 32 movd xmm2, r8d pshufd xmm2, xmm2, 00H psubd xmm2, xmm1 movdqa xmmword ptr [rsp+120H], xmm2 mov rbx, qword ptr [rbp+90H] mov r15, rdx shl r15, 6 movzx r13d, byte ptr [rbp+78H] movzx r12d, byte ptr [rbp+88H] cmp rsi, 4 jc final3blocks outerloop4: movdqu xmm3, xmmword ptr [rcx] pshufd xmm0, xmm3, 00H pshufd xmm1, xmm3, 55H pshufd xmm2, xmm3, 0AAH pshufd xmm3, xmm3, 0FFH movdqu xmm7, xmmword ptr [rcx+10H] pshufd xmm4, xmm7, 00H pshufd xmm5, xmm7, 55H pshufd xmm6, xmm7, 0AAH pshufd xmm7, xmm7, 0FFH mov r8, qword ptr [rdi] mov r9, qword ptr [rdi+8H] mov r10, qword ptr [rdi+10H] mov r11, qword ptr [rdi+18H] movzx eax, byte ptr [rbp+80H] or eax, r13d xor edx, edx innerloop4: mov r14d, eax or eax, r12d add rdx, 64 cmp rdx, r15 cmovne eax, r14d movdqu xmm8, xmmword ptr [r8+rdx-40H] movdqu xmm9, xmmword ptr [r9+rdx-40H] movdqu xmm10, xmmword ptr [r10+rdx-40H] movdqu xmm11, xmmword ptr [r11+rdx-40H] movdqa xmm12, xmm8 punpckldq xmm8, xmm9 punpckhdq xmm12, xmm9 movdqa xmm14, xmm10 punpckldq xmm10, xmm11 punpckhdq xmm14, xmm11 movdqa xmm9, xmm8 punpcklqdq xmm8, xmm10 punpckhqdq xmm9, xmm10 movdqa xmm13, xmm12 punpcklqdq xmm12, xmm14 punpckhqdq xmm13, xmm14 movdqa xmmword ptr [rsp], xmm8 movdqa xmmword ptr [rsp+10H], xmm9 movdqa xmmword ptr [rsp+20H], xmm12 movdqa xmmword ptr [rsp+30H], xmm13 movdqu xmm8, xmmword ptr [r8+rdx-30H] movdqu xmm9, xmmword ptr [r9+rdx-30H] movdqu xmm10, xmmword ptr [r10+rdx-30H] movdqu xmm11, xmmword ptr [r11+rdx-30H] movdqa xmm12, xmm8 punpckldq xmm8, xmm9 punpckhdq xmm12, xmm9 movdqa xmm14, xmm10 punpckldq xmm10, xmm11 punpckhdq xmm14, xmm11 movdqa xmm9, xmm8 punpcklqdq xmm8, xmm10 punpckhqdq xmm9, xmm10 movdqa xmm13, xmm12 punpcklqdq xmm12, xmm14 punpckhqdq xmm13, xmm14 movdqa xmmword ptr [rsp+40H], xmm8 movdqa xmmword ptr [rsp+50H], xmm9 movdqa xmmword ptr [rsp+60H], xmm12 movdqa xmmword ptr [rsp+70H], xmm13 movdqu xmm8, xmmword ptr [r8+rdx-20H] movdqu xmm9, xmmword ptr [r9+rdx-20H] movdqu xmm10, xmmword ptr [r10+rdx-20H] movdqu xmm11, xmmword ptr [r11+rdx-20H] movdqa xmm12, xmm8 punpckldq xmm8, xmm9 punpckhdq xmm12, xmm9 movdqa xmm14, xmm10 punpckldq xmm10, xmm11 punpckhdq xmm14, xmm11 movdqa xmm9, xmm8 punpcklqdq xmm8, xmm10 punpckhqdq xmm9, xmm10 movdqa xmm13, xmm12 punpcklqdq xmm12, xmm14 punpckhqdq xmm13, xmm14 movdqa xmmword ptr [rsp+80H], xmm8 movdqa xmmword ptr [rsp+90H], xmm9 movdqa xmmword ptr [rsp+0A0H], xmm12 movdqa xmmword ptr [rsp+0B0H], xmm13 movdqu xmm8, xmmword ptr [r8+rdx-10H] movdqu xmm9, xmmword ptr [r9+rdx-10H] movdqu xmm10, xmmword ptr [r10+rdx-10H] movdqu xmm11, xmmword ptr [r11+rdx-10H] movdqa xmm12, xmm8 punpckldq xmm8, xmm9 punpckhdq xmm12, xmm9 movdqa xmm14, xmm10 punpckldq xmm10, xmm11 punpckhdq xmm14, xmm11 movdqa xmm9, xmm8 punpcklqdq xmm8, xmm10 punpckhqdq xmm9, xmm10 movdqa xmm13, xmm12 punpcklqdq xmm12, xmm14 punpckhqdq xmm13, xmm14 movdqa xmmword ptr [rsp+0C0H], xmm8 movdqa xmmword ptr [rsp+0D0H], xmm9 movdqa xmmword ptr [rsp+0E0H], xmm12 movdqa xmmword ptr [rsp+0F0H], xmm13 movdqa xmm9, xmmword ptr [BLAKE3_IV_1] movdqa xmm10, xmmword ptr [BLAKE3_IV_2] movdqa xmm11, xmmword ptr [BLAKE3_IV_3] movdqa xmm12, xmmword ptr [rsp+110H] movdqa xmm13, xmmword ptr [rsp+120H] movdqa xmm14, xmmword ptr [BLAKE3_BLOCK_LEN] movd xmm15, eax pshufd xmm15, xmm15, 00H prefetcht0 byte ptr [r8+rdx+80H] prefetcht0 byte ptr [r9+rdx+80H] prefetcht0 byte ptr [r10+rdx+80H] prefetcht0 byte ptr [r11+rdx+80H] paddd xmm0, xmmword ptr [rsp] paddd xmm1, xmmword ptr [rsp+20H] paddd xmm2, xmmword ptr [rsp+40H] paddd xmm3, xmmword ptr [rsp+60H] paddd xmm0, xmm4 paddd xmm1, xmm5 paddd xmm2, xmm6 paddd xmm3, xmm7 pxor xmm12, xmm0 pxor xmm13, xmm1 pxor xmm14, xmm2 pxor xmm15, xmm3 movdqa xmm8, xmmword ptr [ROT16] pshufb xmm12, xmm8 pshufb xmm13, xmm8 pshufb xmm14, xmm8 pshufb xmm15, xmm8 movdqa xmm8, xmmword ptr [BLAKE3_IV_0] paddd xmm8, xmm12 paddd xmm9, xmm13 paddd xmm10, xmm14 paddd xmm11, xmm15 pxor xmm4, xmm8 pxor xmm5, xmm9 pxor xmm6, xmm10 pxor xmm7, xmm11 movdqa xmmword ptr [rsp+100H], xmm8 movdqa xmm8, xmm4 psrld xmm8, 12 pslld xmm4, 20 por xmm4, xmm8 movdqa xmm8, xmm5 psrld xmm8, 12 pslld xmm5, 20 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 12 pslld xmm6, 20 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 12 pslld xmm7, 20 por xmm7, xmm8 paddd xmm0, xmmword ptr [rsp+10H] paddd xmm1, xmmword ptr [rsp+30H] paddd xmm2, xmmword ptr [rsp+50H] paddd xmm3, xmmword ptr [rsp+70H] paddd xmm0, xmm4 paddd xmm1, xmm5 paddd xmm2, xmm6 paddd xmm3, xmm7 pxor xmm12, xmm0 pxor xmm13, xmm1 pxor xmm14, xmm2 pxor xmm15, xmm3 movdqa xmm8, xmmword ptr [ROT8] pshufb xmm12, xmm8 pshufb xmm13, xmm8 pshufb xmm14, xmm8 pshufb xmm15, xmm8 movdqa xmm8, xmmword ptr [rsp+100H] paddd xmm8, xmm12 paddd xmm9, xmm13 paddd xmm10, xmm14 paddd xmm11, xmm15 pxor xmm4, xmm8 pxor xmm5, xmm9 pxor xmm6, xmm10 pxor xmm7, xmm11 movdqa xmmword ptr [rsp+100H], xmm8 movdqa xmm8, xmm4 psrld xmm8, 7 pslld xmm4, 25 por xmm4, xmm8 movdqa xmm8, xmm5 psrld xmm8, 7 pslld xmm5, 25 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 7 pslld xmm6, 25 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 7 pslld xmm7, 25 por xmm7, xmm8 paddd xmm0, xmmword ptr [rsp+80H] paddd xmm1, xmmword ptr [rsp+0A0H] paddd xmm2, xmmword ptr [rsp+0C0H] paddd xmm3, xmmword ptr [rsp+0E0H] paddd xmm0, xmm5 paddd xmm1, xmm6 paddd xmm2, xmm7 paddd xmm3, xmm4 pxor xmm15, xmm0 pxor xmm12, xmm1 pxor xmm13, xmm2 pxor xmm14, xmm3 movdqa xmm8, xmmword ptr [ROT16] pshufb xmm15, xmm8 pshufb xmm12, xmm8 pshufb xmm13, xmm8 pshufb xmm14, xmm8 paddd xmm10, xmm15 paddd xmm11, xmm12 movdqa xmm8, xmmword ptr [rsp+100H] paddd xmm8, xmm13 paddd xmm9, xmm14 pxor xmm5, xmm10 pxor xmm6, xmm11 pxor xmm7, xmm8 pxor xmm4, xmm9 movdqa xmmword ptr [rsp+100H], xmm8 movdqa xmm8, xmm5 psrld xmm8, 12 pslld xmm5, 20 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 12 pslld xmm6, 20 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 12 pslld xmm7, 20 por xmm7, xmm8 movdqa xmm8, xmm4 psrld xmm8, 12 pslld xmm4, 20 por xmm4, xmm8 paddd xmm0, xmmword ptr [rsp+90H] paddd xmm1, xmmword ptr [rsp+0B0H] paddd xmm2, xmmword ptr [rsp+0D0H] paddd xmm3, xmmword ptr [rsp+0F0H] paddd xmm0, xmm5 paddd xmm1, xmm6 paddd xmm2, xmm7 paddd xmm3, xmm4 pxor xmm15, xmm0 pxor xmm12, xmm1 pxor xmm13, xmm2 pxor xmm14, xmm3 movdqa xmm8, xmmword ptr [ROT8] pshufb xmm15, xmm8 pshufb xmm12, xmm8 pshufb xmm13, xmm8 pshufb xmm14, xmm8 paddd xmm10, xmm15 paddd xmm11, xmm12 movdqa xmm8, xmmword ptr [rsp+100H] paddd xmm8, xmm13 paddd xmm9, xmm14 pxor xmm5, xmm10 pxor xmm6, xmm11 pxor xmm7, xmm8 pxor xmm4, xmm9 movdqa xmmword ptr [rsp+100H], xmm8 movdqa xmm8, xmm5 psrld xmm8, 7 pslld xmm5, 25 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 7 pslld xmm6, 25 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 7 pslld xmm7, 25 por xmm7, xmm8 movdqa xmm8, xmm4 psrld xmm8, 7 pslld xmm4, 25 por xmm4, xmm8 paddd xmm0, xmmword ptr [rsp+20H] paddd xmm1, xmmword ptr [rsp+30H] paddd xmm2, xmmword ptr [rsp+70H] paddd xmm3, xmmword ptr [rsp+40H] paddd xmm0, xmm4 paddd xmm1, xmm5 paddd xmm2, xmm6 paddd xmm3, xmm7 pxor xmm12, xmm0 pxor xmm13, xmm1 pxor xmm14, xmm2 pxor xmm15, xmm3 movdqa xmm8, xmmword ptr [ROT16] pshufb xmm12, xmm8 pshufb xmm13, xmm8 pshufb xmm14, xmm8 pshufb xmm15, xmm8 movdqa xmm8, xmmword ptr [rsp+100H] paddd xmm8, xmm12 paddd xmm9, xmm13 paddd xmm10, xmm14 paddd xmm11, xmm15 pxor xmm4, xmm8 pxor xmm5, xmm9 pxor xmm6, xmm10 pxor xmm7, xmm11 movdqa xmmword ptr [rsp+100H], xmm8 movdqa xmm8, xmm4 psrld xmm8, 12 pslld xmm4, 20 por xmm4, xmm8 movdqa xmm8, xmm5 psrld xmm8, 12 pslld xmm5, 20 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 12 pslld xmm6, 20 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 12 pslld xmm7, 20 por xmm7, xmm8 paddd xmm0, xmmword ptr [rsp+60H] paddd xmm1, xmmword ptr [rsp+0A0H] paddd xmm2, xmmword ptr [rsp] paddd xmm3, xmmword ptr [rsp+0D0H] paddd xmm0, xmm4 paddd xmm1, xmm5 paddd xmm2, xmm6 paddd xmm3, xmm7 pxor xmm12, xmm0 pxor xmm13, xmm1 pxor xmm14, xmm2 pxor xmm15, xmm3 movdqa xmm8, xmmword ptr [ROT8] pshufb xmm12, xmm8 pshufb xmm13, xmm8 pshufb xmm14, xmm8 pshufb xmm15, xmm8 movdqa xmm8, xmmword ptr [rsp+100H] paddd xmm8, xmm12 paddd xmm9, xmm13 paddd xmm10, xmm14 paddd xmm11, xmm15 pxor xmm4, xmm8 pxor xmm5, xmm9 pxor xmm6, xmm10 pxor xmm7, xmm11 movdqa xmmword ptr [rsp+100H], xmm8 movdqa xmm8, xmm4 psrld xmm8, 7 pslld xmm4, 25 por xmm4, xmm8 movdqa xmm8, xmm5 psrld xmm8, 7 pslld xmm5, 25 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 7 pslld xmm6, 25 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 7 pslld xmm7, 25 por xmm7, xmm8 paddd xmm0, xmmword ptr [rsp+10H] paddd xmm1, xmmword ptr [rsp+0C0H] paddd xmm2, xmmword ptr [rsp+90H] paddd xmm3, xmmword ptr [rsp+0F0H] paddd xmm0, xmm5 paddd xmm1, xmm6 paddd xmm2, xmm7 paddd xmm3, xmm4 pxor xmm15, xmm0 pxor xmm12, xmm1 pxor xmm13, xmm2 pxor xmm14, xmm3 movdqa xmm8, xmmword ptr [ROT16] pshufb xmm15, xmm8 pshufb xmm12, xmm8 pshufb xmm13, xmm8 pshufb xmm14, xmm8 paddd xmm10, xmm15 paddd xmm11, xmm12 movdqa xmm8, xmmword ptr [rsp+100H] paddd xmm8, xmm13 paddd xmm9, xmm14 pxor xmm5, xmm10 pxor xmm6, xmm11 pxor xmm7, xmm8 pxor xmm4, xmm9 movdqa xmmword ptr [rsp+100H], xmm8 movdqa xmm8, xmm5 psrld xmm8, 12 pslld xmm5, 20 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 12 pslld xmm6, 20 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 12 pslld xmm7, 20 por xmm7, xmm8 movdqa xmm8, xmm4 psrld xmm8, 12 pslld xmm4, 20 por xmm4, xmm8 paddd xmm0, xmmword ptr [rsp+0B0H] paddd xmm1, xmmword ptr [rsp+50H] paddd xmm2, xmmword ptr [rsp+0E0H] paddd xmm3, xmmword ptr [rsp+80H] paddd xmm0, xmm5 paddd xmm1, xmm6 paddd xmm2, xmm7 paddd xmm3, xmm4 pxor xmm15, xmm0 pxor xmm12, xmm1 pxor xmm13, xmm2 pxor xmm14, xmm3 movdqa xmm8, xmmword ptr [ROT8] pshufb xmm15, xmm8 pshufb xmm12, xmm8 pshufb xmm13, xmm8 pshufb xmm14, xmm8 paddd xmm10, xmm15 paddd xmm11, xmm12 movdqa xmm8, xmmword ptr [rsp+100H] paddd xmm8, xmm13 paddd xmm9, xmm14 pxor xmm5, xmm10 pxor xmm6, xmm11 pxor xmm7, xmm8 pxor xmm4, xmm9 movdqa xmmword ptr [rsp+100H], xmm8 movdqa xmm8, xmm5 psrld xmm8, 7 pslld xmm5, 25 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 7 pslld xmm6, 25 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 7 pslld xmm7, 25 por xmm7, xmm8 movdqa xmm8, xmm4 psrld xmm8, 7 pslld xmm4, 25 por xmm4, xmm8 paddd xmm0, xmmword ptr [rsp+30H] paddd xmm1, xmmword ptr [rsp+0A0H] paddd xmm2, xmmword ptr [rsp+0D0H] paddd xmm3, xmmword ptr [rsp+70H] paddd xmm0, xmm4 paddd xmm1, xmm5 paddd xmm2, xmm6 paddd xmm3, xmm7 pxor xmm12, xmm0 pxor xmm13, xmm1 pxor xmm14, xmm2 pxor xmm15, xmm3 movdqa xmm8, xmmword ptr [ROT16] pshufb xmm12, xmm8 pshufb xmm13, xmm8 pshufb xmm14, xmm8 pshufb xmm15, xmm8 movdqa xmm8, xmmword ptr [rsp+100H] paddd xmm8, xmm12 paddd xmm9, xmm13 paddd xmm10, xmm14 paddd xmm11, xmm15 pxor xmm4, xmm8 pxor xmm5, xmm9 pxor xmm6, xmm10 pxor xmm7, xmm11 movdqa xmmword ptr [rsp+100H], xmm8 movdqa xmm8, xmm4 psrld xmm8, 12 pslld xmm4, 20 por xmm4, xmm8 movdqa xmm8, xmm5 psrld xmm8, 12 pslld xmm5, 20 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 12 pslld xmm6, 20 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 12 pslld xmm7, 20 por xmm7, xmm8 paddd xmm0, xmmword ptr [rsp+40H] paddd xmm1, xmmword ptr [rsp+0C0H] paddd xmm2, xmmword ptr [rsp+20H] paddd xmm3, xmmword ptr [rsp+0E0H] paddd xmm0, xmm4 paddd xmm1, xmm5 paddd xmm2, xmm6 paddd xmm3, xmm7 pxor xmm12, xmm0 pxor xmm13, xmm1 pxor xmm14, xmm2 pxor xmm15, xmm3 movdqa xmm8, xmmword ptr [ROT8] pshufb xmm12, xmm8 pshufb xmm13, xmm8 pshufb xmm14, xmm8 pshufb xmm15, xmm8 movdqa xmm8, xmmword ptr [rsp+100H] paddd xmm8, xmm12 paddd xmm9, xmm13 paddd xmm10, xmm14 paddd xmm11, xmm15 pxor xmm4, xmm8 pxor xmm5, xmm9 pxor xmm6, xmm10 pxor xmm7, xmm11 movdqa xmmword ptr [rsp+100H], xmm8 movdqa xmm8, xmm4 psrld xmm8, 7 pslld xmm4, 25 por xmm4, xmm8 movdqa xmm8, xmm5 psrld xmm8, 7 pslld xmm5, 25 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 7 pslld xmm6, 25 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 7 pslld xmm7, 25 por xmm7, xmm8 paddd xmm0, xmmword ptr [rsp+60H] paddd xmm1, xmmword ptr [rsp+90H] paddd xmm2, xmmword ptr [rsp+0B0H] paddd xmm3, xmmword ptr [rsp+80H] paddd xmm0, xmm5 paddd xmm1, xmm6 paddd xmm2, xmm7 paddd xmm3, xmm4 pxor xmm15, xmm0 pxor xmm12, xmm1 pxor xmm13, xmm2 pxor xmm14, xmm3 movdqa xmm8, xmmword ptr [ROT16] pshufb xmm15, xmm8 pshufb xmm12, xmm8 pshufb xmm13, xmm8 pshufb xmm14, xmm8 paddd xmm10, xmm15 paddd xmm11, xmm12 movdqa xmm8, xmmword ptr [rsp+100H] paddd xmm8, xmm13 paddd xmm9, xmm14 pxor xmm5, xmm10 pxor xmm6, xmm11 pxor xmm7, xmm8 pxor xmm4, xmm9 movdqa xmmword ptr [rsp+100H], xmm8 movdqa xmm8, xmm5 psrld xmm8, 12 pslld xmm5, 20 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 12 pslld xmm6, 20 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 12 pslld xmm7, 20 por xmm7, xmm8 movdqa xmm8, xmm4 psrld xmm8, 12 pslld xmm4, 20 por xmm4, xmm8 paddd xmm0, xmmword ptr [rsp+50H] paddd xmm1, xmmword ptr [rsp] paddd xmm2, xmmword ptr [rsp+0F0H] paddd xmm3, xmmword ptr [rsp+10H] paddd xmm0, xmm5 paddd xmm1, xmm6 paddd xmm2, xmm7 paddd xmm3, xmm4 pxor xmm15, xmm0 pxor xmm12, xmm1 pxor xmm13, xmm2 pxor xmm14, xmm3 movdqa xmm8, xmmword ptr [ROT8] pshufb xmm15, xmm8 pshufb xmm12, xmm8 pshufb xmm13, xmm8 pshufb xmm14, xmm8 paddd xmm10, xmm15 paddd xmm11, xmm12 movdqa xmm8, xmmword ptr [rsp+100H] paddd xmm8, xmm13 paddd xmm9, xmm14 pxor xmm5, xmm10 pxor xmm6, xmm11 pxor xmm7, xmm8 pxor xmm4, xmm9 movdqa xmmword ptr [rsp+100H], xmm8 movdqa xmm8, xmm5 psrld xmm8, 7 pslld xmm5, 25 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 7 pslld xmm6, 25 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 7 pslld xmm7, 25 por xmm7, xmm8 movdqa xmm8, xmm4 psrld xmm8, 7 pslld xmm4, 25 por xmm4, xmm8 paddd xmm0, xmmword ptr [rsp+0A0H] paddd xmm1, xmmword ptr [rsp+0C0H] paddd xmm2, xmmword ptr [rsp+0E0H] paddd xmm3, xmmword ptr [rsp+0D0H] paddd xmm0, xmm4 paddd xmm1, xmm5 paddd xmm2, xmm6 paddd xmm3, xmm7 pxor xmm12, xmm0 pxor xmm13, xmm1 pxor xmm14, xmm2 pxor xmm15, xmm3 movdqa xmm8, xmmword ptr [ROT16] pshufb xmm12, xmm8 pshufb xmm13, xmm8 pshufb xmm14, xmm8 pshufb xmm15, xmm8 movdqa xmm8, xmmword ptr [rsp+100H] paddd xmm8, xmm12 paddd xmm9, xmm13 paddd xmm10, xmm14 paddd xmm11, xmm15 pxor xmm4, xmm8 pxor xmm5, xmm9 pxor xmm6, xmm10 pxor xmm7, xmm11 movdqa xmmword ptr [rsp+100H], xmm8 movdqa xmm8, xmm4 psrld xmm8, 12 pslld xmm4, 20 por xmm4, xmm8 movdqa xmm8, xmm5 psrld xmm8, 12 pslld xmm5, 20 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 12 pslld xmm6, 20 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 12 pslld xmm7, 20 por xmm7, xmm8 paddd xmm0, xmmword ptr [rsp+70H] paddd xmm1, xmmword ptr [rsp+90H] paddd xmm2, xmmword ptr [rsp+30H] paddd xmm3, xmmword ptr [rsp+0F0H] paddd xmm0, xmm4 paddd xmm1, xmm5 paddd xmm2, xmm6 paddd xmm3, xmm7 pxor xmm12, xmm0 pxor xmm13, xmm1 pxor xmm14, xmm2 pxor xmm15, xmm3 movdqa xmm8, xmmword ptr [ROT8] pshufb xmm12, xmm8 pshufb xmm13, xmm8 pshufb xmm14, xmm8 pshufb xmm15, xmm8 movdqa xmm8, xmmword ptr [rsp+100H] paddd xmm8, xmm12 paddd xmm9, xmm13 paddd xmm10, xmm14 paddd xmm11, xmm15 pxor xmm4, xmm8 pxor xmm5, xmm9 pxor xmm6, xmm10 pxor xmm7, xmm11 movdqa xmmword ptr [rsp+100H], xmm8 movdqa xmm8, xmm4 psrld xmm8, 7 pslld xmm4, 25 por xmm4, xmm8 movdqa xmm8, xmm5 psrld xmm8, 7 pslld xmm5, 25 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 7 pslld xmm6, 25 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 7 pslld xmm7, 25 por xmm7, xmm8 paddd xmm0, xmmword ptr [rsp+40H] paddd xmm1, xmmword ptr [rsp+0B0H] paddd xmm2, xmmword ptr [rsp+50H] paddd xmm3, xmmword ptr [rsp+10H] paddd xmm0, xmm5 paddd xmm1, xmm6 paddd xmm2, xmm7 paddd xmm3, xmm4 pxor xmm15, xmm0 pxor xmm12, xmm1 pxor xmm13, xmm2 pxor xmm14, xmm3 movdqa xmm8, xmmword ptr [ROT16] pshufb xmm15, xmm8 pshufb xmm12, xmm8 pshufb xmm13, xmm8 pshufb xmm14, xmm8 paddd xmm10, xmm15 paddd xmm11, xmm12 movdqa xmm8, xmmword ptr [rsp+100H] paddd xmm8, xmm13 paddd xmm9, xmm14 pxor xmm5, xmm10 pxor xmm6, xmm11 pxor xmm7, xmm8 pxor xmm4, xmm9 movdqa xmmword ptr [rsp+100H], xmm8 movdqa xmm8, xmm5 psrld xmm8, 12 pslld xmm5, 20 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 12 pslld xmm6, 20 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 12 pslld xmm7, 20 por xmm7, xmm8 movdqa xmm8, xmm4 psrld xmm8, 12 pslld xmm4, 20 por xmm4, xmm8 paddd xmm0, xmmword ptr [rsp] paddd xmm1, xmmword ptr [rsp+20H] paddd xmm2, xmmword ptr [rsp+80H] paddd xmm3, xmmword ptr [rsp+60H] paddd xmm0, xmm5 paddd xmm1, xmm6 paddd xmm2, xmm7 paddd xmm3, xmm4 pxor xmm15, xmm0 pxor xmm12, xmm1 pxor xmm13, xmm2 pxor xmm14, xmm3 movdqa xmm8, xmmword ptr [ROT8] pshufb xmm15, xmm8 pshufb xmm12, xmm8 pshufb xmm13, xmm8 pshufb xmm14, xmm8 paddd xmm10, xmm15 paddd xmm11, xmm12 movdqa xmm8, xmmword ptr [rsp+100H] paddd xmm8, xmm13 paddd xmm9, xmm14 pxor xmm5, xmm10 pxor xmm6, xmm11 pxor xmm7, xmm8 pxor xmm4, xmm9 movdqa xmmword ptr [rsp+100H], xmm8 movdqa xmm8, xmm5 psrld xmm8, 7 pslld xmm5, 25 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 7 pslld xmm6, 25 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 7 pslld xmm7, 25 por xmm7, xmm8 movdqa xmm8, xmm4 psrld xmm8, 7 pslld xmm4, 25 por xmm4, xmm8 paddd xmm0, xmmword ptr [rsp+0C0H] paddd xmm1, xmmword ptr [rsp+90H] paddd xmm2, xmmword ptr [rsp+0F0H] paddd xmm3, xmmword ptr [rsp+0E0H] paddd xmm0, xmm4 paddd xmm1, xmm5 paddd xmm2, xmm6 paddd xmm3, xmm7 pxor xmm12, xmm0 pxor xmm13, xmm1 pxor xmm14, xmm2 pxor xmm15, xmm3 movdqa xmm8, xmmword ptr [ROT16] pshufb xmm12, xmm8 pshufb xmm13, xmm8 pshufb xmm14, xmm8 pshufb xmm15, xmm8 movdqa xmm8, xmmword ptr [rsp+100H] paddd xmm8, xmm12 paddd xmm9, xmm13 paddd xmm10, xmm14 paddd xmm11, xmm15 pxor xmm4, xmm8 pxor xmm5, xmm9 pxor xmm6, xmm10 pxor xmm7, xmm11 movdqa xmmword ptr [rsp+100H], xmm8 movdqa xmm8, xmm4 psrld xmm8, 12 pslld xmm4, 20 por xmm4, xmm8 movdqa xmm8, xmm5 psrld xmm8, 12 pslld xmm5, 20 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 12 pslld xmm6, 20 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 12 pslld xmm7, 20 por xmm7, xmm8 paddd xmm0, xmmword ptr [rsp+0D0H] paddd xmm1, xmmword ptr [rsp+0B0H] paddd xmm2, xmmword ptr [rsp+0A0H] paddd xmm3, xmmword ptr [rsp+80H] paddd xmm0, xmm4 paddd xmm1, xmm5 paddd xmm2, xmm6 paddd xmm3, xmm7 pxor xmm12, xmm0 pxor xmm13, xmm1 pxor xmm14, xmm2 pxor xmm15, xmm3 movdqa xmm8, xmmword ptr [ROT8] pshufb xmm12, xmm8 pshufb xmm13, xmm8 pshufb xmm14, xmm8 pshufb xmm15, xmm8 movdqa xmm8, xmmword ptr [rsp+100H] paddd xmm8, xmm12 paddd xmm9, xmm13 paddd xmm10, xmm14 paddd xmm11, xmm15 pxor xmm4, xmm8 pxor xmm5, xmm9 pxor xmm6, xmm10 pxor xmm7, xmm11 movdqa xmmword ptr [rsp+100H], xmm8 movdqa xmm8, xmm4 psrld xmm8, 7 pslld xmm4, 25 por xmm4, xmm8 movdqa xmm8, xmm5 psrld xmm8, 7 pslld xmm5, 25 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 7 pslld xmm6, 25 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 7 pslld xmm7, 25 por xmm7, xmm8 paddd xmm0, xmmword ptr [rsp+70H] paddd xmm1, xmmword ptr [rsp+50H] paddd xmm2, xmmword ptr [rsp] paddd xmm3, xmmword ptr [rsp+60H] paddd xmm0, xmm5 paddd xmm1, xmm6 paddd xmm2, xmm7 paddd xmm3, xmm4 pxor xmm15, xmm0 pxor xmm12, xmm1 pxor xmm13, xmm2 pxor xmm14, xmm3 movdqa xmm8, xmmword ptr [ROT16] pshufb xmm15, xmm8 pshufb xmm12, xmm8 pshufb xmm13, xmm8 pshufb xmm14, xmm8 paddd xmm10, xmm15 paddd xmm11, xmm12 movdqa xmm8, xmmword ptr [rsp+100H] paddd xmm8, xmm13 paddd xmm9, xmm14 pxor xmm5, xmm10 pxor xmm6, xmm11 pxor xmm7, xmm8 pxor xmm4, xmm9 movdqa xmmword ptr [rsp+100H], xmm8 movdqa xmm8, xmm5 psrld xmm8, 12 pslld xmm5, 20 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 12 pslld xmm6, 20 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 12 pslld xmm7, 20 por xmm7, xmm8 movdqa xmm8, xmm4 psrld xmm8, 12 pslld xmm4, 20 por xmm4, xmm8 paddd xmm0, xmmword ptr [rsp+20H] paddd xmm1, xmmword ptr [rsp+30H] paddd xmm2, xmmword ptr [rsp+10H] paddd xmm3, xmmword ptr [rsp+40H] paddd xmm0, xmm5 paddd xmm1, xmm6 paddd xmm2, xmm7 paddd xmm3, xmm4 pxor xmm15, xmm0 pxor xmm12, xmm1 pxor xmm13, xmm2 pxor xmm14, xmm3 movdqa xmm8, xmmword ptr [ROT8] pshufb xmm15, xmm8 pshufb xmm12, xmm8 pshufb xmm13, xmm8 pshufb xmm14, xmm8 paddd xmm10, xmm15 paddd xmm11, xmm12 movdqa xmm8, xmmword ptr [rsp+100H] paddd xmm8, xmm13 paddd xmm9, xmm14 pxor xmm5, xmm10 pxor xmm6, xmm11 pxor xmm7, xmm8 pxor xmm4, xmm9 movdqa xmmword ptr [rsp+100H], xmm8 movdqa xmm8, xmm5 psrld xmm8, 7 pslld xmm5, 25 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 7 pslld xmm6, 25 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 7 pslld xmm7, 25 por xmm7, xmm8 movdqa xmm8, xmm4 psrld xmm8, 7 pslld xmm4, 25 por xmm4, xmm8 paddd xmm0, xmmword ptr [rsp+90H] paddd xmm1, xmmword ptr [rsp+0B0H] paddd xmm2, xmmword ptr [rsp+80H] paddd xmm3, xmmword ptr [rsp+0F0H] paddd xmm0, xmm4 paddd xmm1, xmm5 paddd xmm2, xmm6 paddd xmm3, xmm7 pxor xmm12, xmm0 pxor xmm13, xmm1 pxor xmm14, xmm2 pxor xmm15, xmm3 movdqa xmm8, xmmword ptr [ROT16] pshufb xmm12, xmm8 pshufb xmm13, xmm8 pshufb xmm14, xmm8 pshufb xmm15, xmm8 movdqa xmm8, xmmword ptr [rsp+100H] paddd xmm8, xmm12 paddd xmm9, xmm13 paddd xmm10, xmm14 paddd xmm11, xmm15 pxor xmm4, xmm8 pxor xmm5, xmm9 pxor xmm6, xmm10 pxor xmm7, xmm11 movdqa xmmword ptr [rsp+100H], xmm8 movdqa xmm8, xmm4 psrld xmm8, 12 pslld xmm4, 20 por xmm4, xmm8 movdqa xmm8, xmm5 psrld xmm8, 12 pslld xmm5, 20 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 12 pslld xmm6, 20 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 12 pslld xmm7, 20 por xmm7, xmm8 paddd xmm0, xmmword ptr [rsp+0E0H] paddd xmm1, xmmword ptr [rsp+50H] paddd xmm2, xmmword ptr [rsp+0C0H] paddd xmm3, xmmword ptr [rsp+10H] paddd xmm0, xmm4 paddd xmm1, xmm5 paddd xmm2, xmm6 paddd xmm3, xmm7 pxor xmm12, xmm0 pxor xmm13, xmm1 pxor xmm14, xmm2 pxor xmm15, xmm3 movdqa xmm8, xmmword ptr [ROT8] pshufb xmm12, xmm8 pshufb xmm13, xmm8 pshufb xmm14, xmm8 pshufb xmm15, xmm8 movdqa xmm8, xmmword ptr [rsp+100H] paddd xmm8, xmm12 paddd xmm9, xmm13 paddd xmm10, xmm14 paddd xmm11, xmm15 pxor xmm4, xmm8 pxor xmm5, xmm9 pxor xmm6, xmm10 pxor xmm7, xmm11 movdqa xmmword ptr [rsp+100H], xmm8 movdqa xmm8, xmm4 psrld xmm8, 7 pslld xmm4, 25 por xmm4, xmm8 movdqa xmm8, xmm5 psrld xmm8, 7 pslld xmm5, 25 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 7 pslld xmm6, 25 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 7 pslld xmm7, 25 por xmm7, xmm8 paddd xmm0, xmmword ptr [rsp+0D0H] paddd xmm1, xmmword ptr [rsp] paddd xmm2, xmmword ptr [rsp+20H] paddd xmm3, xmmword ptr [rsp+40H] paddd xmm0, xmm5 paddd xmm1, xmm6 paddd xmm2, xmm7 paddd xmm3, xmm4 pxor xmm15, xmm0 pxor xmm12, xmm1 pxor xmm13, xmm2 pxor xmm14, xmm3 movdqa xmm8, xmmword ptr [ROT16] pshufb xmm15, xmm8 pshufb xmm12, xmm8 pshufb xmm13, xmm8 pshufb xmm14, xmm8 paddd xmm10, xmm15 paddd xmm11, xmm12 movdqa xmm8, xmmword ptr [rsp+100H] paddd xmm8, xmm13 paddd xmm9, xmm14 pxor xmm5, xmm10 pxor xmm6, xmm11 pxor xmm7, xmm8 pxor xmm4, xmm9 movdqa xmmword ptr [rsp+100H], xmm8 movdqa xmm8, xmm5 psrld xmm8, 12 pslld xmm5, 20 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 12 pslld xmm6, 20 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 12 pslld xmm7, 20 por xmm7, xmm8 movdqa xmm8, xmm4 psrld xmm8, 12 pslld xmm4, 20 por xmm4, xmm8 paddd xmm0, xmmword ptr [rsp+30H] paddd xmm1, xmmword ptr [rsp+0A0H] paddd xmm2, xmmword ptr [rsp+60H] paddd xmm3, xmmword ptr [rsp+70H] paddd xmm0, xmm5 paddd xmm1, xmm6 paddd xmm2, xmm7 paddd xmm3, xmm4 pxor xmm15, xmm0 pxor xmm12, xmm1 pxor xmm13, xmm2 pxor xmm14, xmm3 movdqa xmm8, xmmword ptr [ROT8] pshufb xmm15, xmm8 pshufb xmm12, xmm8 pshufb xmm13, xmm8 pshufb xmm14, xmm8 paddd xmm10, xmm15 paddd xmm11, xmm12 movdqa xmm8, xmmword ptr [rsp+100H] paddd xmm8, xmm13 paddd xmm9, xmm14 pxor xmm5, xmm10 pxor xmm6, xmm11 pxor xmm7, xmm8 pxor xmm4, xmm9 movdqa xmmword ptr [rsp+100H], xmm8 movdqa xmm8, xmm5 psrld xmm8, 7 pslld xmm5, 25 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 7 pslld xmm6, 25 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 7 pslld xmm7, 25 por xmm7, xmm8 movdqa xmm8, xmm4 psrld xmm8, 7 pslld xmm4, 25 por xmm4, xmm8 paddd xmm0, xmmword ptr [rsp+0B0H] paddd xmm1, xmmword ptr [rsp+50H] paddd xmm2, xmmword ptr [rsp+10H] paddd xmm3, xmmword ptr [rsp+80H] paddd xmm0, xmm4 paddd xmm1, xmm5 paddd xmm2, xmm6 paddd xmm3, xmm7 pxor xmm12, xmm0 pxor xmm13, xmm1 pxor xmm14, xmm2 pxor xmm15, xmm3 movdqa xmm8, xmmword ptr [ROT16] pshufb xmm12, xmm8 pshufb xmm13, xmm8 pshufb xmm14, xmm8 pshufb xmm15, xmm8 movdqa xmm8, xmmword ptr [rsp+100H] paddd xmm8, xmm12 paddd xmm9, xmm13 paddd xmm10, xmm14 paddd xmm11, xmm15 pxor xmm4, xmm8 pxor xmm5, xmm9 pxor xmm6, xmm10 pxor xmm7, xmm11 movdqa xmmword ptr [rsp+100H], xmm8 movdqa xmm8, xmm4 psrld xmm8, 12 pslld xmm4, 20 por xmm4, xmm8 movdqa xmm8, xmm5 psrld xmm8, 12 pslld xmm5, 20 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 12 pslld xmm6, 20 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 12 pslld xmm7, 20 por xmm7, xmm8 paddd xmm0, xmmword ptr [rsp+0F0H] paddd xmm1, xmmword ptr [rsp] paddd xmm2, xmmword ptr [rsp+90H] paddd xmm3, xmmword ptr [rsp+60H] paddd xmm0, xmm4 paddd xmm1, xmm5 paddd xmm2, xmm6 paddd xmm3, xmm7 pxor xmm12, xmm0 pxor xmm13, xmm1 pxor xmm14, xmm2 pxor xmm15, xmm3 movdqa xmm8, xmmword ptr [ROT8] pshufb xmm12, xmm8 pshufb xmm13, xmm8 pshufb xmm14, xmm8 pshufb xmm15, xmm8 movdqa xmm8, xmmword ptr [rsp+100H] paddd xmm8, xmm12 paddd xmm9, xmm13 paddd xmm10, xmm14 paddd xmm11, xmm15 pxor xmm4, xmm8 pxor xmm5, xmm9 pxor xmm6, xmm10 pxor xmm7, xmm11 movdqa xmmword ptr [rsp+100H], xmm8 movdqa xmm8, xmm4 psrld xmm8, 7 pslld xmm4, 25 por xmm4, xmm8 movdqa xmm8, xmm5 psrld xmm8, 7 pslld xmm5, 25 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 7 pslld xmm6, 25 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 7 pslld xmm7, 25 por xmm7, xmm8 paddd xmm0, xmmword ptr [rsp+0E0H] paddd xmm1, xmmword ptr [rsp+20H] paddd xmm2, xmmword ptr [rsp+30H] paddd xmm3, xmmword ptr [rsp+70H] paddd xmm0, xmm5 paddd xmm1, xmm6 paddd xmm2, xmm7 paddd xmm3, xmm4 pxor xmm15, xmm0 pxor xmm12, xmm1 pxor xmm13, xmm2 pxor xmm14, xmm3 movdqa xmm8, xmmword ptr [ROT16] pshufb xmm15, xmm8 pshufb xmm12, xmm8 pshufb xmm13, xmm8 pshufb xmm14, xmm8 paddd xmm10, xmm15 paddd xmm11, xmm12 movdqa xmm8, xmmword ptr [rsp+100H] paddd xmm8, xmm13 paddd xmm9, xmm14 pxor xmm5, xmm10 pxor xmm6, xmm11 pxor xmm7, xmm8 pxor xmm4, xmm9 movdqa xmmword ptr [rsp+100H], xmm8 movdqa xmm8, xmm5 psrld xmm8, 12 pslld xmm5, 20 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 12 pslld xmm6, 20 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 12 pslld xmm7, 20 por xmm7, xmm8 movdqa xmm8, xmm4 psrld xmm8, 12 pslld xmm4, 20 por xmm4, xmm8 paddd xmm0, xmmword ptr [rsp+0A0H] paddd xmm1, xmmword ptr [rsp+0C0H] paddd xmm2, xmmword ptr [rsp+40H] paddd xmm3, xmmword ptr [rsp+0D0H] paddd xmm0, xmm5 paddd xmm1, xmm6 paddd xmm2, xmm7 paddd xmm3, xmm4 pxor xmm15, xmm0 pxor xmm12, xmm1 pxor xmm13, xmm2 pxor xmm14, xmm3 movdqa xmm8, xmmword ptr [ROT8] pshufb xmm15, xmm8 pshufb xmm12, xmm8 pshufb xmm13, xmm8 pshufb xmm14, xmm8 paddd xmm10, xmm15 paddd xmm11, xmm12 movdqa xmm8, xmmword ptr [rsp+100H] paddd xmm8, xmm13 paddd xmm9, xmm14 pxor xmm5, xmm10 pxor xmm6, xmm11 pxor xmm7, xmm8 pxor xmm4, xmm9 pxor xmm0, xmm8 pxor xmm1, xmm9 pxor xmm2, xmm10 pxor xmm3, xmm11 movdqa xmm8, xmm5 psrld xmm8, 7 pslld xmm5, 25 por xmm5, xmm8 movdqa xmm8, xmm6 psrld xmm8, 7 pslld xmm6, 25 por xmm6, xmm8 movdqa xmm8, xmm7 psrld xmm8, 7 pslld xmm7, 25 por xmm7, xmm8 movdqa xmm8, xmm4 psrld xmm8, 7 pslld xmm4, 25 por xmm4, xmm8 pxor xmm4, xmm12 pxor xmm5, xmm13 pxor xmm6, xmm14 pxor xmm7, xmm15 mov eax, r13d jne innerloop4 movdqa xmm9, xmm0 punpckldq xmm0, xmm1 punpckhdq xmm9, xmm1 movdqa xmm11, xmm2 punpckldq xmm2, xmm3 punpckhdq xmm11, xmm3 movdqa xmm1, xmm0 punpcklqdq xmm0, xmm2 punpckhqdq xmm1, xmm2 movdqa xmm3, xmm9 punpcklqdq xmm9, xmm11 punpckhqdq xmm3, xmm11 movdqu xmmword ptr [rbx], xmm0 movdqu xmmword ptr [rbx+20H], xmm1 movdqu xmmword ptr [rbx+40H], xmm9 movdqu xmmword ptr [rbx+60H], xmm3 movdqa xmm9, xmm4 punpckldq xmm4, xmm5 punpckhdq xmm9, xmm5 movdqa xmm11, xmm6 punpckldq xmm6, xmm7 punpckhdq xmm11, xmm7 movdqa xmm5, xmm4 punpcklqdq xmm4, xmm6 punpckhqdq xmm5, xmm6 movdqa xmm7, xmm9 punpcklqdq xmm9, xmm11 punpckhqdq xmm7, xmm11 movdqu xmmword ptr [rbx+10H], xmm4 movdqu xmmword ptr [rbx+30H], xmm5 movdqu xmmword ptr [rbx+50H], xmm9 movdqu xmmword ptr [rbx+70H], xmm7 movdqa xmm1, xmmword ptr [rsp+110H] movdqa xmm0, xmm1 paddd xmm1, xmmword ptr [rsp+150H] movdqa xmmword ptr [rsp+110H], xmm1 pxor xmm0, xmmword ptr [CMP_MSB_MASK] pxor xmm1, xmmword ptr [CMP_MSB_MASK] pcmpgtd xmm0, xmm1 movdqa xmm1, xmmword ptr [rsp+120H] psubd xmm1, xmm0 movdqa xmmword ptr [rsp+120H], xmm1 add rbx, 128 add rdi, 32 sub rsi, 4 cmp rsi, 4 jnc outerloop4 test rsi, rsi jne final3blocks unwind: movdqa xmm6, xmmword ptr [rsp+170H] movdqa xmm7, xmmword ptr [rsp+180H] movdqa xmm8, xmmword ptr [rsp+190H] movdqa xmm9, xmmword ptr [rsp+1A0H] movdqa xmm10, xmmword ptr [rsp+1B0H] movdqa xmm11, xmmword ptr [rsp+1C0H] movdqa xmm12, xmmword ptr [rsp+1D0H] movdqa xmm13, xmmword ptr [rsp+1E0H] movdqa xmm14, xmmword ptr [rsp+1F0H] movdqa xmm15, xmmword ptr [rsp+200H] mov rsp, rbp pop rbp pop rbx pop rdi pop rsi pop r12 pop r13 pop r14 pop r15 ret ALIGN 16 final3blocks: test esi, 2H je final1block movups xmm0, xmmword ptr [rcx] movups xmm1, xmmword ptr [rcx+10H] movaps xmm8, xmm0 movaps xmm9, xmm1 movd xmm13, dword ptr [rsp+110H] pinsrd xmm13, dword ptr [rsp+120H], 1 pinsrd xmm13, dword ptr [BLAKE3_BLOCK_LEN], 2 movaps xmmword ptr [rsp], xmm13 movd xmm14, dword ptr [rsp+114H] pinsrd xmm14, dword ptr [rsp+124H], 1 pinsrd xmm14, dword ptr [BLAKE3_BLOCK_LEN], 2 movaps xmmword ptr [rsp+10H], xmm14 mov r8, qword ptr [rdi] mov r9, qword ptr [rdi+8H] movzx eax, byte ptr [rbp+80H] or eax, r13d xor edx, edx innerloop2: mov r14d, eax or eax, r12d add rdx, 64 cmp rdx, r15 cmovne eax, r14d movaps xmm2, xmmword ptr [BLAKE3_IV] movaps xmm10, xmm2 movups xmm4, xmmword ptr [r8+rdx-40H] movups xmm5, xmmword ptr [r8+rdx-30H] movaps xmm3, xmm4 shufps xmm4, xmm5, 136 shufps xmm3, xmm5, 221 movaps xmm5, xmm3 movups xmm6, xmmword ptr [r8+rdx-20H] movups xmm7, xmmword ptr [r8+rdx-10H] movaps xmm3, xmm6 shufps xmm6, xmm7, 136 pshufd xmm6, xmm6, 93H shufps xmm3, xmm7, 221 pshufd xmm7, xmm3, 93H movups xmm12, xmmword ptr [r9+rdx-40H] movups xmm13, xmmword ptr [r9+rdx-30H] movaps xmm11, xmm12 shufps xmm12, xmm13, 136 shufps xmm11, xmm13, 221 movaps xmm13, xmm11 movups xmm14, xmmword ptr [r9+rdx-20H] movups xmm15, xmmword ptr [r9+rdx-10H] movaps xmm11, xmm14 shufps xmm14, xmm15, 136 pshufd xmm14, xmm14, 93H shufps xmm11, xmm15, 221 pshufd xmm15, xmm11, 93H movaps xmm3, xmmword ptr [rsp] movaps xmm11, xmmword ptr [rsp+10H] pinsrd xmm3, eax, 3 pinsrd xmm11, eax, 3 mov al, 7 roundloop2: paddd xmm0, xmm4 paddd xmm8, xmm12 movaps xmmword ptr [rsp+20H], xmm4 movaps xmmword ptr [rsp+30H], xmm12 paddd xmm0, xmm1 paddd xmm8, xmm9 pxor xmm3, xmm0 pxor xmm11, xmm8 movaps xmm12, xmmword ptr [ROT16] pshufb xmm3, xmm12 pshufb xmm11, xmm12 paddd xmm2, xmm3 paddd xmm10, xmm11 pxor xmm1, xmm2 pxor xmm9, xmm10 movdqa xmm4, xmm1 pslld xmm1, 20 psrld xmm4, 12 por xmm1, xmm4 movdqa xmm4, xmm9 pslld xmm9, 20 psrld xmm4, 12 por xmm9, xmm4 paddd xmm0, xmm5 paddd xmm8, xmm13 movaps xmmword ptr [rsp+40H], xmm5 movaps xmmword ptr [rsp+50H], xmm13 paddd xmm0, xmm1 paddd xmm8, xmm9 pxor xmm3, xmm0 pxor xmm11, xmm8 movaps xmm13, xmmword ptr [ROT8] pshufb xmm3, xmm13 pshufb xmm11, xmm13 paddd xmm2, xmm3 paddd xmm10, xmm11 pxor xmm1, xmm2 pxor xmm9, xmm10 movdqa xmm4, xmm1 pslld xmm1, 25 psrld xmm4, 7 por xmm1, xmm4 movdqa xmm4, xmm9 pslld xmm9, 25 psrld xmm4, 7 por xmm9, xmm4 pshufd xmm0, xmm0, 93H pshufd xmm8, xmm8, 93H pshufd xmm3, xmm3, 4EH pshufd xmm11, xmm11, 4EH pshufd xmm2, xmm2, 39H pshufd xmm10, xmm10, 39H paddd xmm0, xmm6 paddd xmm8, xmm14 paddd xmm0, xmm1 paddd xmm8, xmm9 pxor xmm3, xmm0 pxor xmm11, xmm8 pshufb xmm3, xmm12 pshufb xmm11, xmm12 paddd xmm2, xmm3 paddd xmm10, xmm11 pxor xmm1, xmm2 pxor xmm9, xmm10 movdqa xmm4, xmm1 pslld xmm1, 20 psrld xmm4, 12 por xmm1, xmm4 movdqa xmm4, xmm9 pslld xmm9, 20 psrld xmm4, 12 por xmm9, xmm4 paddd xmm0, xmm7 paddd xmm8, xmm15 paddd xmm0, xmm1 paddd xmm8, xmm9 pxor xmm3, xmm0 pxor xmm11, xmm8 pshufb xmm3, xmm13 pshufb xmm11, xmm13 paddd xmm2, xmm3 paddd xmm10, xmm11 pxor xmm1, xmm2 pxor xmm9, xmm10 movdqa xmm4, xmm1 pslld xmm1, 25 psrld xmm4, 7 por xmm1, xmm4 movdqa xmm4, xmm9 pslld xmm9, 25 psrld xmm4, 7 por xmm9, xmm4 pshufd xmm0, xmm0, 39H pshufd xmm8, xmm8, 39H pshufd xmm3, xmm3, 4EH pshufd xmm11, xmm11, 4EH pshufd xmm2, xmm2, 93H pshufd xmm10, xmm10, 93H dec al je endroundloop2 movdqa xmm12, xmmword ptr [rsp+20H] movdqa xmm5, xmmword ptr [rsp+40H] pshufd xmm13, xmm12, 0FH shufps xmm12, xmm5, 214 pshufd xmm4, xmm12, 39H movdqa xmm12, xmm6 shufps xmm12, xmm7, 250 pblendw xmm13, xmm12, 0CCH movdqa xmm12, xmm7 punpcklqdq xmm12, xmm5 pblendw xmm12, xmm6, 0C0H pshufd xmm12, xmm12, 78H punpckhdq xmm5, xmm7 punpckldq xmm6, xmm5 pshufd xmm7, xmm6, 1EH movdqa xmmword ptr [rsp+20H], xmm13 movdqa xmmword ptr [rsp+40H], xmm12 movdqa xmm5, xmmword ptr [rsp+30H] movdqa xmm13, xmmword ptr [rsp+50H] pshufd xmm6, xmm5, 0FH shufps xmm5, xmm13, 214 pshufd xmm12, xmm5, 39H movdqa xmm5, xmm14 shufps xmm5, xmm15, 250 pblendw xmm6, xmm5, 0CCH movdqa xmm5, xmm15 punpcklqdq xmm5, xmm13 pblendw xmm5, xmm14, 0C0H pshufd xmm5, xmm5, 78H punpckhdq xmm13, xmm15 punpckldq xmm14, xmm13 pshufd xmm15, xmm14, 1EH movdqa xmm13, xmm6 movdqa xmm14, xmm5 movdqa xmm5, xmmword ptr [rsp+20H] movdqa xmm6, xmmword ptr [rsp+40H] jmp roundloop2 endroundloop2: pxor xmm0, xmm2 pxor xmm1, xmm3 pxor xmm8, xmm10 pxor xmm9, xmm11 mov eax, r13d cmp rdx, r15 jne innerloop2 movups xmmword ptr [rbx], xmm0 movups xmmword ptr [rbx+10H], xmm1 movups xmmword ptr [rbx+20H], xmm8 movups xmmword ptr [rbx+30H], xmm9 movdqa xmm0, xmmword ptr [rsp+130H] movdqa xmm1, xmmword ptr [rsp+110H] movdqa xmm2, xmmword ptr [rsp+120H] movdqu xmm3, xmmword ptr [rsp+118H] movdqu xmm4, xmmword ptr [rsp+128H] blendvps xmm1, xmm3, xmm0 blendvps xmm2, xmm4, xmm0 movdqa xmmword ptr [rsp+110H], xmm1 movdqa xmmword ptr [rsp+120H], xmm2 add rdi, 16 add rbx, 64 sub rsi, 2 final1block: test esi, 1H je unwind movups xmm0, xmmword ptr [rcx] movups xmm1, xmmword ptr [rcx+10H] movd xmm13, dword ptr [rsp+110H] pinsrd xmm13, dword ptr [rsp+120H], 1 pinsrd xmm13, dword ptr [BLAKE3_BLOCK_LEN], 2 movaps xmm14, xmmword ptr [ROT8] movaps xmm15, xmmword ptr [ROT16] mov r8, qword ptr [rdi] movzx eax, byte ptr [rbp+80H] or eax, r13d xor edx, edx innerloop1: mov r14d, eax or eax, r12d add rdx, 64 cmp rdx, r15 cmovne eax, r14d movaps xmm2, xmmword ptr [BLAKE3_IV] movaps xmm3, xmm13 pinsrd xmm3, eax, 3 movups xmm4, xmmword ptr [r8+rdx-40H] movups xmm5, xmmword ptr [r8+rdx-30H] movaps xmm8, xmm4 shufps xmm4, xmm5, 136 shufps xmm8, xmm5, 221 movaps xmm5, xmm8 movups xmm6, xmmword ptr [r8+rdx-20H] movups xmm7, xmmword ptr [r8+rdx-10H] movaps xmm8, xmm6 shufps xmm6, xmm7, 136 pshufd xmm6, xmm6, 93H shufps xmm8, xmm7, 221 pshufd xmm7, xmm8, 93H mov al, 7 roundloop1: paddd xmm0, xmm4 paddd xmm0, xmm1 pxor xmm3, xmm0 pshufb xmm3, xmm15 paddd xmm2, xmm3 pxor xmm1, xmm2 movdqa xmm11, xmm1 pslld xmm1, 20 psrld xmm11, 12 por xmm1, xmm11 paddd xmm0, xmm5 paddd xmm0, xmm1 pxor xmm3, xmm0 pshufb xmm3, xmm14 paddd xmm2, xmm3 pxor xmm1, xmm2 movdqa xmm11, xmm1 pslld xmm1, 25 psrld xmm11, 7 por xmm1, xmm11 pshufd xmm0, xmm0, 93H pshufd xmm3, xmm3, 4EH pshufd xmm2, xmm2, 39H paddd xmm0, xmm6 paddd xmm0, xmm1 pxor xmm3, xmm0 pshufb xmm3, xmm15 paddd xmm2, xmm3 pxor xmm1, xmm2 movdqa xmm11, xmm1 pslld xmm1, 20 psrld xmm11, 12 por xmm1, xmm11 paddd xmm0, xmm7 paddd xmm0, xmm1 pxor xmm3, xmm0 pshufb xmm3, xmm14 paddd xmm2, xmm3 pxor xmm1, xmm2 movdqa xmm11, xmm1 pslld xmm1, 25 psrld xmm11, 7 por xmm1, xmm11 pshufd xmm0, xmm0, 39H pshufd xmm3, xmm3, 4EH pshufd xmm2, xmm2, 93H dec al jz endroundloop1 movdqa xmm8, xmm4 shufps xmm8, xmm5, 214 pshufd xmm9, xmm4, 0FH pshufd xmm4, xmm8, 39H movdqa xmm8, xmm6 shufps xmm8, xmm7, 250 pblendw xmm9, xmm8, 0CCH movdqa xmm8, xmm7 punpcklqdq xmm8, xmm5 pblendw xmm8, xmm6, 0C0H pshufd xmm8, xmm8, 78H punpckhdq xmm5, xmm7 punpckldq xmm6, xmm5 pshufd xmm7, xmm6, 1EH movdqa xmm5, xmm9 movdqa xmm6, xmm8 jmp roundloop1 endroundloop1: pxor xmm0, xmm2 pxor xmm1, xmm3 mov eax, r13d cmp rdx, r15 jne innerloop1 movups xmmword ptr [rbx], xmm0 movups xmmword ptr [rbx+10H], xmm1 jmp unwind _blake3_hash_many_sse41 ENDP blake3_hash_many_sse41 ENDP blake3_compress_in_place_sse41 PROC _blake3_compress_in_place_sse41 PROC sub rsp, 120 movdqa xmmword ptr [rsp], xmm6 movdqa xmmword ptr [rsp+10H], xmm7 movdqa xmmword ptr [rsp+20H], xmm8 movdqa xmmword ptr [rsp+30H], xmm9 movdqa xmmword ptr [rsp+40H], xmm11 movdqa xmmword ptr [rsp+50H], xmm14 movdqa xmmword ptr [rsp+60H], xmm15 movups xmm0, xmmword ptr [rcx] movups xmm1, xmmword ptr [rcx+10H] movaps xmm2, xmmword ptr [BLAKE3_IV] movzx eax, byte ptr [rsp+0A0H] movzx r8d, r8b shl rax, 32 add r8, rax movd xmm3, r9 movd xmm4, r8 punpcklqdq xmm3, xmm4 movups xmm4, xmmword ptr [rdx] movups xmm5, xmmword ptr [rdx+10H] movaps xmm8, xmm4 shufps xmm4, xmm5, 136 shufps xmm8, xmm5, 221 movaps xmm5, xmm8 movups xmm6, xmmword ptr [rdx+20H] movups xmm7, xmmword ptr [rdx+30H] movaps xmm8, xmm6 shufps xmm6, xmm7, 136 pshufd xmm6, xmm6, 93H shufps xmm8, xmm7, 221 pshufd xmm7, xmm8, 93H movaps xmm14, xmmword ptr [ROT8] movaps xmm15, xmmword ptr [ROT16] mov al, 7 @@: paddd xmm0, xmm4 paddd xmm0, xmm1 pxor xmm3, xmm0 pshufb xmm3, xmm15 paddd xmm2, xmm3 pxor xmm1, xmm2 movdqa xmm11, xmm1 pslld xmm1, 20 psrld xmm11, 12 por xmm1, xmm11 paddd xmm0, xmm5 paddd xmm0, xmm1 pxor xmm3, xmm0 pshufb xmm3, xmm14 paddd xmm2, xmm3 pxor xmm1, xmm2 movdqa xmm11, xmm1 pslld xmm1, 25 psrld xmm11, 7 por xmm1, xmm11 pshufd xmm0, xmm0, 93H pshufd xmm3, xmm3, 4EH pshufd xmm2, xmm2, 39H paddd xmm0, xmm6 paddd xmm0, xmm1 pxor xmm3, xmm0 pshufb xmm3, xmm15 paddd xmm2, xmm3 pxor xmm1, xmm2 movdqa xmm11, xmm1 pslld xmm1, 20 psrld xmm11, 12 por xmm1, xmm11 paddd xmm0, xmm7 paddd xmm0, xmm1 pxor xmm3, xmm0 pshufb xmm3, xmm14 paddd xmm2, xmm3 pxor xmm1, xmm2 movdqa xmm11, xmm1 pslld xmm1, 25 psrld xmm11, 7 por xmm1, xmm11 pshufd xmm0, xmm0, 39H pshufd xmm3, xmm3, 4EH pshufd xmm2, xmm2, 93H dec al jz @F movdqa xmm8, xmm4 shufps xmm8, xmm5, 214 pshufd xmm9, xmm4, 0FH pshufd xmm4, xmm8, 39H movdqa xmm8, xmm6 shufps xmm8, xmm7, 250 pblendw xmm9, xmm8, 0CCH movdqa xmm8, xmm7 punpcklqdq xmm8, xmm5 pblendw xmm8, xmm6, 0C0H pshufd xmm8, xmm8, 78H punpckhdq xmm5, xmm7 punpckldq xmm6, xmm5 pshufd xmm7, xmm6, 1EH movdqa xmm5, xmm9 movdqa xmm6, xmm8 jmp @B @@: pxor xmm0, xmm2 pxor xmm1, xmm3 movups xmmword ptr [rcx], xmm0 movups xmmword ptr [rcx+10H], xmm1 movdqa xmm6, xmmword ptr [rsp] movdqa xmm7, xmmword ptr [rsp+10H] movdqa xmm8, xmmword ptr [rsp+20H] movdqa xmm9, xmmword ptr [rsp+30H] movdqa xmm11, xmmword ptr [rsp+40H] movdqa xmm14, xmmword ptr [rsp+50H] movdqa xmm15, xmmword ptr [rsp+60H] add rsp, 120 ret _blake3_compress_in_place_sse41 ENDP blake3_compress_in_place_sse41 ENDP ALIGN 16 blake3_compress_xof_sse41 PROC _blake3_compress_xof_sse41 PROC sub rsp, 120 movdqa xmmword ptr [rsp], xmm6 movdqa xmmword ptr [rsp+10H], xmm7 movdqa xmmword ptr [rsp+20H], xmm8 movdqa xmmword ptr [rsp+30H], xmm9 movdqa xmmword ptr [rsp+40H], xmm11 movdqa xmmword ptr [rsp+50H], xmm14 movdqa xmmword ptr [rsp+60H], xmm15 movups xmm0, xmmword ptr [rcx] movups xmm1, xmmword ptr [rcx+10H] movaps xmm2, xmmword ptr [BLAKE3_IV] movzx eax, byte ptr [rsp+0A0H] movzx r8d, r8b mov r10, qword ptr [rsp+0A8H] shl rax, 32 add r8, rax movd xmm3, r9 movd xmm4, r8 punpcklqdq xmm3, xmm4 movups xmm4, xmmword ptr [rdx] movups xmm5, xmmword ptr [rdx+10H] movaps xmm8, xmm4 shufps xmm4, xmm5, 136 shufps xmm8, xmm5, 221 movaps xmm5, xmm8 movups xmm6, xmmword ptr [rdx+20H] movups xmm7, xmmword ptr [rdx+30H] movaps xmm8, xmm6 shufps xmm6, xmm7, 136 pshufd xmm6, xmm6, 93H shufps xmm8, xmm7, 221 pshufd xmm7, xmm8, 93H movaps xmm14, xmmword ptr [ROT8] movaps xmm15, xmmword ptr [ROT16] mov al, 7 @@: paddd xmm0, xmm4 paddd xmm0, xmm1 pxor xmm3, xmm0 pshufb xmm3, xmm15 paddd xmm2, xmm3 pxor xmm1, xmm2 movdqa xmm11, xmm1 pslld xmm1, 20 psrld xmm11, 12 por xmm1, xmm11 paddd xmm0, xmm5 paddd xmm0, xmm1 pxor xmm3, xmm0 pshufb xmm3, xmm14 paddd xmm2, xmm3 pxor xmm1, xmm2 movdqa xmm11, xmm1 pslld xmm1, 25 psrld xmm11, 7 por xmm1, xmm11 pshufd xmm0, xmm0, 93H pshufd xmm3, xmm3, 4EH pshufd xmm2, xmm2, 39H paddd xmm0, xmm6 paddd xmm0, xmm1 pxor xmm3, xmm0 pshufb xmm3, xmm15 paddd xmm2, xmm3 pxor xmm1, xmm2 movdqa xmm11, xmm1 pslld xmm1, 20 psrld xmm11, 12 por xmm1, xmm11 paddd xmm0, xmm7 paddd xmm0, xmm1 pxor xmm3, xmm0 pshufb xmm3, xmm14 paddd xmm2, xmm3 pxor xmm1, xmm2 movdqa xmm11, xmm1 pslld xmm1, 25 psrld xmm11, 7 por xmm1, xmm11 pshufd xmm0, xmm0, 39H pshufd xmm3, xmm3, 4EH pshufd xmm2, xmm2, 93H dec al jz @F movdqa xmm8, xmm4 shufps xmm8, xmm5, 214 pshufd xmm9, xmm4, 0FH pshufd xmm4, xmm8, 39H movdqa xmm8, xmm6 shufps xmm8, xmm7, 250 pblendw xmm9, xmm8, 0CCH movdqa xmm8, xmm7 punpcklqdq xmm8, xmm5 pblendw xmm8, xmm6, 0C0H pshufd xmm8, xmm8, 78H punpckhdq xmm5, xmm7 punpckldq xmm6, xmm5 pshufd xmm7, xmm6, 1EH movdqa xmm5, xmm9 movdqa xmm6, xmm8 jmp @B @@: movdqu xmm4, xmmword ptr [rcx] movdqu xmm5, xmmword ptr [rcx+10H] pxor xmm0, xmm2 pxor xmm1, xmm3 pxor xmm2, xmm4 pxor xmm3, xmm5 movups xmmword ptr [r10], xmm0 movups xmmword ptr [r10+10H], xmm1 movups xmmword ptr [r10+20H], xmm2 movups xmmword ptr [r10+30H], xmm3 movdqa xmm6, xmmword ptr [rsp] movdqa xmm7, xmmword ptr [rsp+10H] movdqa xmm8, xmmword ptr [rsp+20H] movdqa xmm9, xmmword ptr [rsp+30H] movdqa xmm11, xmmword ptr [rsp+40H] movdqa xmm14, xmmword ptr [rsp+50H] movdqa xmm15, xmmword ptr [rsp+60H] add rsp, 120 ret _blake3_compress_xof_sse41 ENDP blake3_compress_xof_sse41 ENDP _TEXT ENDS _RDATA SEGMENT READONLY PAGE ALIAS(".rdata") 'CONST' ALIGN 64 BLAKE3_IV: dd 6A09E667H, 0BB67AE85H, 3C6EF372H, 0A54FF53AH ADD0: dd 0, 1, 2, 3 ADD1: dd 4 dup (4) BLAKE3_IV_0: dd 4 dup (6A09E667H) BLAKE3_IV_1: dd 4 dup (0BB67AE85H) BLAKE3_IV_2: dd 4 dup (3C6EF372H) BLAKE3_IV_3: dd 4 dup (0A54FF53AH) BLAKE3_BLOCK_LEN: dd 4 dup (64) ROT16: db 2, 3, 0, 1, 6, 7, 4, 5, 10, 11, 8, 9, 14, 15, 12, 13 ROT8: db 1, 2, 3, 0, 5, 6, 7, 4, 9, 10, 11, 8, 13, 14, 15, 12 CMP_MSB_MASK: dd 8 dup(80000000H) _RDATA ENDS END librecast/libs/blake3/c/example.c000066400000000000000000000015441502456746400171620ustar00rootroot00000000000000#include "blake3.h" #include #include #include #include int main(void) { // Initialize the hasher. blake3_hasher hasher; blake3_hasher_init(&hasher); // Read input bytes from stdin. unsigned char buf[65536]; while (1) { ssize_t n = read(STDIN_FILENO, buf, sizeof(buf)); if (n > 0) { blake3_hasher_update(&hasher, buf, n); } else if (n == 0) { break; // end of file } else { fprintf(stderr, "read failed: %s\n", strerror(errno)); return 1; } } // Finalize the hash. BLAKE3_OUT_LEN is the default output length, 32 bytes. uint8_t output[BLAKE3_OUT_LEN]; blake3_hasher_finalize(&hasher, output, BLAKE3_OUT_LEN); // Print the hash as hexadecimal. for (size_t i = 0; i < BLAKE3_OUT_LEN; i++) { printf("%02x", output[i]); } printf("\n"); return 0; } librecast/libs/blake3/c/main.c000066400000000000000000000077131502456746400164570ustar00rootroot00000000000000/* * This main file is intended for testing via `make test`. It does not build in * other settings. See README.md in this directory for examples of how to build * C code. */ #include #include #include #include #include #include #include "blake3.h" #include "blake3_impl.h" #define HASH_MODE 0 #define KEYED_HASH_MODE 1 #define DERIVE_KEY_MODE 2 static void hex_char_value(uint8_t c, uint8_t *value, bool *valid) { if ('0' <= c && c <= '9') { *value = c - '0'; *valid = true; } else if ('a' <= c && c <= 'f') { *value = 10 + c - 'a'; *valid = true; } else { *valid = false; } } static int parse_key(char *hex_key, uint8_t out[BLAKE3_KEY_LEN]) { size_t hex_len = strlen(hex_key); if (hex_len != 64) { fprintf(stderr, "Expected a 64-char hexadecimal key, got %zu chars.\n", hex_len); return 1; } for (size_t i = 0; i < 64; i++) { uint8_t value; bool valid; hex_char_value(hex_key[i], &value, &valid); if (!valid) { fprintf(stderr, "Invalid hex char.\n"); return 1; } if (i % 2 == 0) { out[i / 2] = 0; value <<= 4; } out[i / 2] += value; } return 0; } /* A little repetition here */ enum cpu_feature { SSE2 = 1 << 0, SSSE3 = 1 << 1, SSE41 = 1 << 2, AVX = 1 << 3, AVX2 = 1 << 4, AVX512F = 1 << 5, AVX512VL = 1 << 6, /* ... */ UNDEFINED = 1 << 30 }; extern enum cpu_feature g_cpu_features; enum cpu_feature get_cpu_features(void); int main(int argc, char **argv) { size_t out_len = BLAKE3_OUT_LEN; uint8_t key[BLAKE3_KEY_LEN]; char *context = ""; uint8_t mode = HASH_MODE; while (argc > 1) { if (argc <= 2) { fprintf(stderr, "Odd number of arguments.\n"); return 1; } if (strcmp("--length", argv[1]) == 0) { char *endptr = NULL; errno = 0; unsigned long long out_len_ll = strtoull(argv[2], &endptr, 10); if (errno != 0 || out_len_ll > SIZE_MAX || endptr == argv[2] || *endptr != 0) { fprintf(stderr, "Bad length argument.\n"); return 1; } out_len = (size_t)out_len_ll; } else if (strcmp("--keyed", argv[1]) == 0) { mode = KEYED_HASH_MODE; int ret = parse_key(argv[2], key); if (ret != 0) { return ret; } } else if (strcmp("--derive-key", argv[1]) == 0) { mode = DERIVE_KEY_MODE; context = argv[2]; } else { fprintf(stderr, "Unknown flag.\n"); return 1; } argc -= 2; argv += 2; } /* * We're going to hash the input multiple times, so we need to buffer it all. * This is just for test cases, so go ahead and assume that the input is less * than 1 MiB. */ size_t buf_capacity = 1 << 20; uint8_t *buf = malloc(buf_capacity); assert(buf != NULL); size_t buf_len = 0; while (1) { size_t n = fread(&buf[buf_len], 1, buf_capacity - buf_len, stdin); if (n == 0) { break; } buf_len += n; assert(buf_len < buf_capacity); } const int mask = get_cpu_features(); int feature = 0; do { fprintf(stderr, "Testing 0x%08X\n", feature); g_cpu_features = feature; blake3_hasher hasher; switch (mode) { case HASH_MODE: blake3_hasher_init(&hasher); break; case KEYED_HASH_MODE: blake3_hasher_init_keyed(&hasher, key); break; case DERIVE_KEY_MODE: blake3_hasher_init_derive_key(&hasher, context); break; default: abort(); } blake3_hasher_update(&hasher, buf, buf_len); /* TODO: An incremental output reader API to avoid this allocation. */ uint8_t *out = malloc(out_len); if (out_len > 0 && out == NULL) { fprintf(stderr, "malloc() failed.\n"); return 1; } blake3_hasher_finalize(&hasher, out, out_len); for (size_t i = 0; i < out_len; i++) { printf("%02x", out[i]); } printf("\n"); free(out); feature = (feature - mask) & mask; } while (feature != 0); free(buf); return 0; } librecast/libs/blake3/c/test.py000077500000000000000000000071061502456746400167170ustar00rootroot00000000000000#! /usr/bin/env python3 from binascii import hexlify import json from os import path import subprocess HERE = path.dirname(__file__) TEST_VECTORS_PATH = path.join(HERE, "..", "test_vectors", "test_vectors.json") TEST_VECTORS = json.load(open(TEST_VECTORS_PATH)) def run_blake3(args, input): output = subprocess.run([path.join(HERE, "blake3")] + args, input=input, stdout=subprocess.PIPE, check=True) return output.stdout.decode().strip() # Fill the input with a repeating byte pattern. We use a cycle length of 251, # because that's the largest prime number less than 256. This makes it unlikely # to swapping any two adjacent input blocks or chunks will give the same # answer. def make_test_input(length): i = 0 buf = bytearray() while len(buf) < length: buf.append(i) i = (i + 1) % 251 return buf def main(): for case in TEST_VECTORS["cases"]: input_len = case["input_len"] input = make_test_input(input_len) hex_key = hexlify(TEST_VECTORS["key"].encode()) context_string = TEST_VECTORS["context_string"] expected_hash_xof = case["hash"] expected_hash = expected_hash_xof[:64] expected_keyed_hash_xof = case["keyed_hash"] expected_keyed_hash = expected_keyed_hash_xof[:64] expected_derive_key_xof = case["derive_key"] expected_derive_key = expected_derive_key_xof[:64] # Test the default hash. test_hash = run_blake3([], input) for line in test_hash.splitlines(): assert expected_hash == line, \ "hash({}): {} != {}".format(input_len, expected_hash, line) # Test the extended hash. xof_len = len(expected_hash_xof) // 2 test_hash_xof = run_blake3(["--length", str(xof_len)], input) for line in test_hash_xof.splitlines(): assert expected_hash_xof == line, \ "hash_xof({}): {} != {}".format( input_len, expected_hash_xof, line) # Test the default keyed hash. test_keyed_hash = run_blake3(["--keyed", hex_key], input) for line in test_keyed_hash.splitlines(): assert expected_keyed_hash == line, \ "keyed_hash({}): {} != {}".format( input_len, expected_keyed_hash, line) # Test the extended keyed hash. xof_len = len(expected_keyed_hash_xof) // 2 test_keyed_hash_xof = run_blake3( ["--keyed", hex_key, "--length", str(xof_len)], input) for line in test_keyed_hash_xof.splitlines(): assert expected_keyed_hash_xof == line, \ "keyed_hash_xof({}): {} != {}".format( input_len, expected_keyed_hash_xof, line) # Test the default derive key. test_derive_key = run_blake3(["--derive-key", context_string], input) for line in test_derive_key.splitlines(): assert expected_derive_key == line, \ "derive_key({}): {} != {}".format( input_len, expected_derive_key, line) # Test the extended derive key. xof_len = len(expected_derive_key_xof) // 2 test_derive_key_xof = run_blake3( ["--derive-key", context_string, "--length", str(xof_len)], input) for line in test_derive_key_xof.splitlines(): assert expected_derive_key_xof == line, \ "derive_key_xof({}): {} != {}".format( input_len, expected_derive_key_xof, line) if __name__ == "__main__": main() librecast/libs/libmld/000077500000000000000000000000001502456746400152375ustar00rootroot00000000000000librecast/libs/libmld/.gitignore000066400000000000000000000002661502456746400172330ustar00rootroot00000000000000*.o *.so* *.swp cov-int/ *.tgz gmon.out profile.* autom4te.cache/ autoscan-2.71.log configure~ config.status config.log Makefile src/Makefile test/Makefile src/config.h src/libmld.a librecast/libs/libmld/CODE_OF_CONDUCT.md000066400000000000000000000064251502456746400200450ustar00rootroot00000000000000# Contributor Covenant Code of Conduct ## Our Pledge In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, religion, or sexual identity and orientation. ## Our Standards Examples of behavior that contributes to creating a positive environment include: * Using welcoming and inclusive language * Being respectful of differing viewpoints and experiences * Gracefully accepting constructive criticism * Focusing on what is best for the community * Showing empathy towards other community members Examples of unacceptable behavior by participants include: * The use of sexualized language or imagery and unwelcome sexual attention or advances * Trolling, insulting/derogatory comments, and personal or political attacks * Public or private harassment * Publishing others' private information, such as a physical or electronic address, without explicit permission * Other conduct which could reasonably be considered inappropriate in a professional setting ## Our Responsibilities Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. ## Scope This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. ## Enforcement Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at coc@librecast.net. All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. ## Attribution This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html [homepage]: https://www.contributor-covenant.org For answers to common questions about this code of conduct, see https://www.contributor-covenant.org/faq librecast/libs/libmld/CONTRIBUTING.md000066400000000000000000000024561502456746400174770ustar00rootroot00000000000000# CONTRIBUTING Contributions are very welcome, both large and small. Correct patches (see Patch Requirements) will generally be accepted. This is a small project, so I don't want to get bogged down in too much formality, but in general I'm striving to follow Pieter Hintjens' Collective Code Construction Contract (C4) as used by the ZeroMQ project: https://rfc.zeromq.org/spec:42/C4/ ## Patch Requirements Maintainers and Contributors MUST have a Platform account and SHOULD use their real names or a well-known alias. A patch SHOULD be a minimal and accurate answer to exactly one identified and agreed problem. A patch MUST adhere to the code style guidelines of the project (see below) A patch SHALL NOT include non-trivial code from other projects unless the Contributor is the original author of that code. A patch MUST compile cleanly and pass project self-tests on at least the principal target platform. A patch commit message SHOULD consist of a single short (less than 50 character) line summarizing the change, optionally followed by a blank line and then a more thorough description. A "Correct Patch" is one that satisfies the above requirements. ## Coding Style This project uses the Linux kernel coding style: See https://www.kernel.org/doc/html/latest/process/coding-style.html librecast/libs/libmld/COPYING000066400000000000000000000017311502456746400162740ustar00rootroot00000000000000The software is largely licensed under the terms of the GPL-2.0 or at your option, GPL-3.0. Individual files are marked with with SPDX-License-Identifier to indicate which terms they are licensed under: SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only The full terms of the GPL-2.0 are in LICENSE.GPL-2.0-only and GPL-3.0 are in and LICENSE.GPL-3.0-only. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) version 3 of the license. 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 . librecast/libs/libmld/LICENSE.GPL-2.0-only000066400000000000000000000444511502456746400201510ustar00rootroot00000000000000Valid-License-Identifier: GPL-2.0 Valid-License-Identifier: GPL-2.0-only Valid-License-Identifier: GPL-2.0+ Valid-License-Identifier: GPL-2.0-or-later SPDX-URL: https://spdx.org/licenses/GPL-2.0.html Usage-Guide: To use this license in source code, put one of the following SPDX tag/value pairs into a comment according to the placement guidelines in the licensing rules documentation. For 'GNU General Public License (GPL) version 2 only' use: SPDX-License-Identifier: GPL-2.0 or SPDX-License-Identifier: GPL-2.0-only For 'GNU General Public License (GPL) version 2 or any later version' use: SPDX-License-Identifier: GPL-2.0+ or SPDX-License-Identifier: GPL-2.0-or-later License-Text: GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. librecast/libs/libmld/LICENSE.GPL-3.0-only000066400000000000000000001045131502456746400201460ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 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 . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Copyright (C) This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . librecast/libs/libmld/Makefile.in000066400000000000000000000055411502456746400173110ustar00rootroot00000000000000# SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only # Copyright (c) 2020-2023 Brett Sheffield SHELL := bash .SUFFIXES: .SUFFIXES: .c .o export CC = @CC@ export CFLAGS = @CFLAGS@ export CPPFLAGS = @CPPFLAGS@ export INSTALL = @INSTALL@ export INSTALL_DATA = @INSTALL_DATA@ export INSTALL_PROGRAM = @INSTALL_PROGRAM@ export INSTALL_SCRIPT = @INSTALL_SCRIPT@ export LDFLAGS = @LDFLAGS@ export LDLIBS = @LIBS@ export PACKAGE = @PACKAGE_NAME@ export PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ export PACKAGE_NAME = @PACKAGE_NAME@ export PACKAGE_STRING = @PACKAGE_STRING@ export PACKAGE_TARNAME = @PACKAGE_TARNAME@ export PACKAGE_URL = @PACKAGE_URL@ export PACKAGE_VERSION = @PACKAGE_VERSION@ export PROGRAM = @PACKAGE_NAME@ export SHELL = @SHELL@ export bindir = @bindir@ export builddir = @builddir@ export datadir = @datadir@ export datarootdir = @datarootdir@ export exec_prefix = @exec_prefix@ export mandir = @mandir@ export prefix = @prefix@ export srcdir = @srcdir@ .PHONY: all clean src test testloop check install net-setup net-teardown setcap testfiles all: src install uninstall setcap: all $(MAKE) -C src $@ src: $(MAKE) -C $@ clean: $(MAKE) -C src $@ $(MAKE) -C test $@ realclean: clean $(MAKE) -C src $@ $(MAKE) -C test $@ $(RM) Makefile config.{log,status} include/mld.h fixme: grep -n FIXME src/*.{c,h} test/*.{c,h} todo: grep -n TODO src/*.{c,h} test/*.{c,h} sparse: clean CC=cgcc $(MAKE) src clang: clean CC=clang $(MAKE) CFLAGS+="$(CFLAGS-CLANG)" src clangtest: clang CC=clang $(MAKE) CFLAGS+="$(CFLAGS-CLANG)" test gcc: clean all %.clang: CC=clang $(MAKE) CFLAGS+="$(CFLAGS-CLANG)" -B -C test $@ test memcheck: src $(MAKE) -C test $@/all LOOPBANNER ?= echo testloop: num_ok=0; \ while $(MAKE) $(subst testloop,test,$@); do \ num_ok=$$(( $$num_ok + 1 )); \ echo; \ echo; \ $(LOOPBANNER) "OK $$num_ok"; \ echo; \ sleep 2; \ done; \ $(LOOPBANNER) "OK $$num_ok" testloop/%: num_ok=0; \ while $(MAKE) $(subst testloop,test,$@); do \ num_ok=$$(( $$num_ok + 1 )); \ echo; \ echo; \ $(LOOPBANNER) "OK $$num_ok"; \ echo; \ sleep 2; \ done; \ $(LOOPBANNER) "OK $$num_ok" test/% memcheck/%: .FORCE src $(MAKE) -C test $@ .FORCE: # always recompile net-setup: ip link add veth0 type veth peer name veth1 ip netns add vnet0 ip netns add vnet1 ip link set veth0 netns vnet0 ip link set veth1 netns vnet1 ip -n vnet0 link set veth0 up ip -n vnet1 link set veth1 up ip netns show net-teardown: ip -n vnet0 link set veth0 down ip -n vnet1 link set veth1 down ip -n vnet1 link set veth1 netns vnet0 ip -n vnet0 link del veth0 type veth peer name veth1 ip netns del vnet0 ip netns del vnet1 ip netns show testfiles: @dir="/tmp/lcsync/testfiles" ; \ echo $$dir ; \ mkdir -p $$dir; \ for z in {1..10}; do \ c=$$((2 ** $$z * 1024)); \ echo $$c; \ dd if=/dev/random of=$$dir/testfile.$$z bs=1024 count=$$c; \ done librecast/libs/libmld/README.md000066400000000000000000000005541502456746400165220ustar00rootroot00000000000000# libmld - IPv6 Muliticast Listener Discovery (MLD2) library ``` ./configure make make test # NB: some tests require root/CAP_NET_RAW ``` ## Bloom Filters (experimental) NB: this option has been temporarily removed. To enable the experimental SIMD bloom filters call configure with the appropriate option before building: `./configure --enable-bloom-filters` librecast/libs/libmld/config.guess000066400000000000000000001412021502456746400175540ustar00rootroot00000000000000#! /bin/sh # Attempt to guess a canonical system name. # Copyright 1992-2022 Free Software Foundation, Inc. # shellcheck disable=SC2006,SC2268 # see below for rationale timestamp='2022-05-25' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 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 . # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that # program. This Exception is an additional permission under section 7 # of the GNU General Public License, version 3 ("GPLv3"). # # Originally written by Per Bothner; maintained since 2000 by Ben Elliston. # # You can get the latest version of this script from: # https://git.savannah.gnu.org/cgit/config.git/plain/config.guess # # Please send patches to . # The "shellcheck disable" line above the timestamp inhibits complaints # about features and limitations of the classic Bourne shell that were # superseded or lifted in POSIX. However, this script identifies a wide # variety of pre-POSIX systems that do not have POSIX shells at all, and # even some reasonably current systems (Solaris 10 as case-in-point) still # have a pre-POSIX /bin/sh. me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] Output the configuration name of the system \`$me' is run on. Options: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.guess ($timestamp) Originally written by Per Bothner. Copyright 1992-2022 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit ;; --version | -v ) echo "$version" ; exit ;; --help | --h* | -h ) echo "$usage"; exit ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" >&2 exit 1 ;; * ) break ;; esac done if test $# != 0; then echo "$me: too many arguments$help" >&2 exit 1 fi # Just in case it came from the environment. GUESS= # CC_FOR_BUILD -- compiler used by this script. Note that the use of a # compiler to aid in system detection is discouraged as it requires # temporary files to be created and, as you can see below, it is a # headache to deal with in a portable fashion. # Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still # use `HOST_CC' if defined, but it is deprecated. # Portable tmp directory creation inspired by the Autoconf team. tmp= # shellcheck disable=SC2172 trap 'test -z "$tmp" || rm -fr "$tmp"' 0 1 2 13 15 set_cc_for_build() { # prevent multiple calls if $tmp is already set test "$tmp" && return 0 : "${TMPDIR=/tmp}" # shellcheck disable=SC2039,SC3028 { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir "$tmp" 2>/dev/null) ; } || { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir "$tmp" 2>/dev/null) && echo "Warning: creating insecure temp directory" >&2 ; } || { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } dummy=$tmp/dummy case ${CC_FOR_BUILD-},${HOST_CC-},${CC-} in ,,) echo "int x;" > "$dummy.c" for driver in cc gcc c89 c99 ; do if ($driver -c -o "$dummy.o" "$dummy.c") >/dev/null 2>&1 ; then CC_FOR_BUILD=$driver break fi done if test x"$CC_FOR_BUILD" = x ; then CC_FOR_BUILD=no_compiler_found fi ;; ,,*) CC_FOR_BUILD=$CC ;; ,*,*) CC_FOR_BUILD=$HOST_CC ;; esac } # This is needed to find uname on a Pyramid OSx when run in the BSD universe. # (ghazi@noc.rutgers.edu 1994-08-24) if test -f /.attbin/uname ; then PATH=$PATH:/.attbin ; export PATH fi UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown case $UNAME_SYSTEM in Linux|GNU|GNU/*) LIBC=unknown set_cc_for_build cat <<-EOF > "$dummy.c" #include #if defined(__UCLIBC__) LIBC=uclibc #elif defined(__dietlibc__) LIBC=dietlibc #elif defined(__GLIBC__) LIBC=gnu #else #include /* First heuristic to detect musl libc. */ #ifdef __DEFINED_va_list LIBC=musl #endif #endif EOF cc_set_libc=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^LIBC' | sed 's, ,,g'` eval "$cc_set_libc" # Second heuristic to detect musl libc. if [ "$LIBC" = unknown ] && command -v ldd >/dev/null && ldd --version 2>&1 | grep -q ^musl; then LIBC=musl fi # If the system lacks a compiler, then just pick glibc. # We could probably try harder. if [ "$LIBC" = unknown ]; then LIBC=gnu fi ;; esac # Note: order is significant - the case branches are not exclusive. case $UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION in *:NetBSD:*:*) # NetBSD (nbsd) targets should (where applicable) match one or # more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*, # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently # switched to ELF, *-*-netbsd* would select the old # object file format. This provides both forward # compatibility and a consistent mechanism for selecting the # object file format. # # Note: NetBSD doesn't particularly care about the vendor # portion of the name. We always set it to "unknown". UNAME_MACHINE_ARCH=`(uname -p 2>/dev/null || \ /sbin/sysctl -n hw.machine_arch 2>/dev/null || \ /usr/sbin/sysctl -n hw.machine_arch 2>/dev/null || \ echo unknown)` case $UNAME_MACHINE_ARCH in aarch64eb) machine=aarch64_be-unknown ;; armeb) machine=armeb-unknown ;; arm*) machine=arm-unknown ;; sh3el) machine=shl-unknown ;; sh3eb) machine=sh-unknown ;; sh5el) machine=sh5le-unknown ;; earmv*) arch=`echo "$UNAME_MACHINE_ARCH" | sed -e 's,^e\(armv[0-9]\).*$,\1,'` endian=`echo "$UNAME_MACHINE_ARCH" | sed -ne 's,^.*\(eb\)$,\1,p'` machine=${arch}${endian}-unknown ;; *) machine=$UNAME_MACHINE_ARCH-unknown ;; esac # The Operating System including object format, if it has switched # to ELF recently (or will in the future) and ABI. case $UNAME_MACHINE_ARCH in earm*) os=netbsdelf ;; arm*|i386|m68k|ns32k|sh3*|sparc|vax) set_cc_for_build if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ELF__ then # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). # Return netbsd for either. FIX? os=netbsd else os=netbsdelf fi ;; *) os=netbsd ;; esac # Determine ABI tags. case $UNAME_MACHINE_ARCH in earm*) expr='s/^earmv[0-9]/-eabi/;s/eb$//' abi=`echo "$UNAME_MACHINE_ARCH" | sed -e "$expr"` ;; esac # The OS release # Debian GNU/NetBSD machines have a different userland, and # thus, need a distinct triplet. However, they do not need # kernel version information, so it can be replaced with a # suitable tag, in the style of linux-gnu. case $UNAME_VERSION in Debian*) release='-gnu' ;; *) release=`echo "$UNAME_RELEASE" | sed -e 's/[-_].*//' | cut -d. -f1,2` ;; esac # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: # contains redundant information, the shorter form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. GUESS=$machine-${os}${release}${abi-} ;; *:Bitrig:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'` GUESS=$UNAME_MACHINE_ARCH-unknown-bitrig$UNAME_RELEASE ;; *:OpenBSD:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` GUESS=$UNAME_MACHINE_ARCH-unknown-openbsd$UNAME_RELEASE ;; *:SecBSD:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/SecBSD.//'` GUESS=$UNAME_MACHINE_ARCH-unknown-secbsd$UNAME_RELEASE ;; *:LibertyBSD:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/^.*BSD\.//'` GUESS=$UNAME_MACHINE_ARCH-unknown-libertybsd$UNAME_RELEASE ;; *:MidnightBSD:*:*) GUESS=$UNAME_MACHINE-unknown-midnightbsd$UNAME_RELEASE ;; *:ekkoBSD:*:*) GUESS=$UNAME_MACHINE-unknown-ekkobsd$UNAME_RELEASE ;; *:SolidBSD:*:*) GUESS=$UNAME_MACHINE-unknown-solidbsd$UNAME_RELEASE ;; *:OS108:*:*) GUESS=$UNAME_MACHINE-unknown-os108_$UNAME_RELEASE ;; macppc:MirBSD:*:*) GUESS=powerpc-unknown-mirbsd$UNAME_RELEASE ;; *:MirBSD:*:*) GUESS=$UNAME_MACHINE-unknown-mirbsd$UNAME_RELEASE ;; *:Sortix:*:*) GUESS=$UNAME_MACHINE-unknown-sortix ;; *:Twizzler:*:*) GUESS=$UNAME_MACHINE-unknown-twizzler ;; *:Redox:*:*) GUESS=$UNAME_MACHINE-unknown-redox ;; mips:OSF1:*.*) GUESS=mips-dec-osf1 ;; alpha:OSF1:*:*) # Reset EXIT trap before exiting to avoid spurious non-zero exit code. trap '' 0 case $UNAME_RELEASE in *4.0) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` ;; *5.*) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` ;; esac # According to Compaq, /usr/sbin/psrinfo has been available on # OSF/1 and Tru64 systems produced since 1995. I hope that # covers most systems running today. This code pipes the CPU # types through head -n 1, so we only detect the type of CPU 0. ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` case $ALPHA_CPU_TYPE in "EV4 (21064)") UNAME_MACHINE=alpha ;; "EV4.5 (21064)") UNAME_MACHINE=alpha ;; "LCA4 (21066/21068)") UNAME_MACHINE=alpha ;; "EV5 (21164)") UNAME_MACHINE=alphaev5 ;; "EV5.6 (21164A)") UNAME_MACHINE=alphaev56 ;; "EV5.6 (21164PC)") UNAME_MACHINE=alphapca56 ;; "EV5.7 (21164PC)") UNAME_MACHINE=alphapca57 ;; "EV6 (21264)") UNAME_MACHINE=alphaev6 ;; "EV6.7 (21264A)") UNAME_MACHINE=alphaev67 ;; "EV6.8CB (21264C)") UNAME_MACHINE=alphaev68 ;; "EV6.8AL (21264B)") UNAME_MACHINE=alphaev68 ;; "EV6.8CX (21264D)") UNAME_MACHINE=alphaev68 ;; "EV6.9A (21264/EV69A)") UNAME_MACHINE=alphaev69 ;; "EV7 (21364)") UNAME_MACHINE=alphaev7 ;; "EV7.9 (21364A)") UNAME_MACHINE=alphaev79 ;; esac # A Pn.n version is a patched version. # A Vn.n version is a released version. # A Tn.n version is a released field test version. # A Xn.n version is an unreleased experimental baselevel. # 1.2 uses "1.2" for uname -r. OSF_REL=`echo "$UNAME_RELEASE" | sed -e 's/^[PVTX]//' | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz` GUESS=$UNAME_MACHINE-dec-osf$OSF_REL ;; Amiga*:UNIX_System_V:4.0:*) GUESS=m68k-unknown-sysv4 ;; *:[Aa]miga[Oo][Ss]:*:*) GUESS=$UNAME_MACHINE-unknown-amigaos ;; *:[Mm]orph[Oo][Ss]:*:*) GUESS=$UNAME_MACHINE-unknown-morphos ;; *:OS/390:*:*) GUESS=i370-ibm-openedition ;; *:z/VM:*:*) GUESS=s390-ibm-zvmoe ;; *:OS400:*:*) GUESS=powerpc-ibm-os400 ;; arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) GUESS=arm-acorn-riscix$UNAME_RELEASE ;; arm*:riscos:*:*|arm*:RISCOS:*:*) GUESS=arm-unknown-riscos ;; SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) GUESS=hppa1.1-hitachi-hiuxmpp ;; Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. case `(/bin/universe) 2>/dev/null` in att) GUESS=pyramid-pyramid-sysv3 ;; *) GUESS=pyramid-pyramid-bsd ;; esac ;; NILE*:*:*:dcosx) GUESS=pyramid-pyramid-svr4 ;; DRS?6000:unix:4.0:6*) GUESS=sparc-icl-nx6 ;; DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) case `/usr/bin/uname -p` in sparc) GUESS=sparc-icl-nx7 ;; esac ;; s390x:SunOS:*:*) SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` GUESS=$UNAME_MACHINE-ibm-solaris2$SUN_REL ;; sun4H:SunOS:5.*:*) SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` GUESS=sparc-hal-solaris2$SUN_REL ;; sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` GUESS=sparc-sun-solaris2$SUN_REL ;; i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*) GUESS=i386-pc-auroraux$UNAME_RELEASE ;; i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) set_cc_for_build SUN_ARCH=i386 # If there is a compiler, see if it is configured for 64-bit objects. # Note that the Sun cc does not turn __LP64__ into 1 like gcc does. # This test works for both compilers. if test "$CC_FOR_BUILD" != no_compiler_found; then if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \ (CCOPTS="" $CC_FOR_BUILD -m64 -E - 2>/dev/null) | \ grep IS_64BIT_ARCH >/dev/null then SUN_ARCH=x86_64 fi fi SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` GUESS=$SUN_ARCH-pc-solaris2$SUN_REL ;; sun4*:SunOS:6*:*) # According to config.sub, this is the proper way to canonicalize # SunOS6. Hard to guess exactly what SunOS6 will be like, but # it's likely to be more like Solaris than SunOS4. SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` GUESS=sparc-sun-solaris3$SUN_REL ;; sun4*:SunOS:*:*) case `/usr/bin/arch -k` in Series*|S4*) UNAME_RELEASE=`uname -v` ;; esac # Japanese Language versions have a version number like `4.1.3-JL'. SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/-/_/'` GUESS=sparc-sun-sunos$SUN_REL ;; sun3*:SunOS:*:*) GUESS=m68k-sun-sunos$UNAME_RELEASE ;; sun*:*:4.2BSD:*) UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` test "x$UNAME_RELEASE" = x && UNAME_RELEASE=3 case `/bin/arch` in sun3) GUESS=m68k-sun-sunos$UNAME_RELEASE ;; sun4) GUESS=sparc-sun-sunos$UNAME_RELEASE ;; esac ;; aushp:SunOS:*:*) GUESS=sparc-auspex-sunos$UNAME_RELEASE ;; # The situation for MiNT is a little confusing. The machine name # can be virtually everything (everything which is not # "atarist" or "atariste" at least should have a processor # > m68000). The system name ranges from "MiNT" over "FreeMiNT" # to the lowercase version "mint" (or "freemint"). Finally # the system name "TOS" denotes a system which is actually not # MiNT. But MiNT is downward compatible to TOS, so this should # be no problem. atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) GUESS=m68k-atari-mint$UNAME_RELEASE ;; atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) GUESS=m68k-atari-mint$UNAME_RELEASE ;; *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) GUESS=m68k-atari-mint$UNAME_RELEASE ;; milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) GUESS=m68k-milan-mint$UNAME_RELEASE ;; hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) GUESS=m68k-hades-mint$UNAME_RELEASE ;; *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) GUESS=m68k-unknown-mint$UNAME_RELEASE ;; m68k:machten:*:*) GUESS=m68k-apple-machten$UNAME_RELEASE ;; powerpc:machten:*:*) GUESS=powerpc-apple-machten$UNAME_RELEASE ;; RISC*:Mach:*:*) GUESS=mips-dec-mach_bsd4.3 ;; RISC*:ULTRIX:*:*) GUESS=mips-dec-ultrix$UNAME_RELEASE ;; VAX*:ULTRIX*:*:*) GUESS=vax-dec-ultrix$UNAME_RELEASE ;; 2020:CLIX:*:* | 2430:CLIX:*:*) GUESS=clipper-intergraph-clix$UNAME_RELEASE ;; mips:*:*:UMIPS | mips:*:*:RISCos) set_cc_for_build sed 's/^ //' << EOF > "$dummy.c" #ifdef __cplusplus #include /* for printf() prototype */ int main (int argc, char *argv[]) { #else int main (argc, argv) int argc; char *argv[]; { #endif #if defined (host_mips) && defined (MIPSEB) #if defined (SYSTYPE_SYSV) printf ("mips-mips-riscos%ssysv\\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_SVR4) printf ("mips-mips-riscos%ssvr4\\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) printf ("mips-mips-riscos%sbsd\\n", argv[1]); exit (0); #endif #endif exit (-1); } EOF $CC_FOR_BUILD -o "$dummy" "$dummy.c" && dummyarg=`echo "$UNAME_RELEASE" | sed -n 's/\([0-9]*\).*/\1/p'` && SYSTEM_NAME=`"$dummy" "$dummyarg"` && { echo "$SYSTEM_NAME"; exit; } GUESS=mips-mips-riscos$UNAME_RELEASE ;; Motorola:PowerMAX_OS:*:*) GUESS=powerpc-motorola-powermax ;; Motorola:*:4.3:PL8-*) GUESS=powerpc-harris-powermax ;; Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) GUESS=powerpc-harris-powermax ;; Night_Hawk:Power_UNIX:*:*) GUESS=powerpc-harris-powerunix ;; m88k:CX/UX:7*:*) GUESS=m88k-harris-cxux7 ;; m88k:*:4*:R4*) GUESS=m88k-motorola-sysv4 ;; m88k:*:3*:R3*) GUESS=m88k-motorola-sysv3 ;; AViiON:dgux:*:*) # DG/UX returns AViiON for all architectures UNAME_PROCESSOR=`/usr/bin/uname -p` if test "$UNAME_PROCESSOR" = mc88100 || test "$UNAME_PROCESSOR" = mc88110 then if test "$TARGET_BINARY_INTERFACE"x = m88kdguxelfx || \ test "$TARGET_BINARY_INTERFACE"x = x then GUESS=m88k-dg-dgux$UNAME_RELEASE else GUESS=m88k-dg-dguxbcs$UNAME_RELEASE fi else GUESS=i586-dg-dgux$UNAME_RELEASE fi ;; M88*:DolphinOS:*:*) # DolphinOS (SVR3) GUESS=m88k-dolphin-sysv3 ;; M88*:*:R3*:*) # Delta 88k system running SVR3 GUESS=m88k-motorola-sysv3 ;; XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) GUESS=m88k-tektronix-sysv3 ;; Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) GUESS=m68k-tektronix-bsd ;; *:IRIX*:*:*) IRIX_REL=`echo "$UNAME_RELEASE" | sed -e 's/-/_/g'` GUESS=mips-sgi-irix$IRIX_REL ;; ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. GUESS=romp-ibm-aix # uname -m gives an 8 hex-code CPU id ;; # Note that: echo "'`uname -s`'" gives 'AIX ' i*86:AIX:*:*) GUESS=i386-ibm-aix ;; ia64:AIX:*:*) if test -x /usr/bin/oslevel ; then IBM_REV=`/usr/bin/oslevel` else IBM_REV=$UNAME_VERSION.$UNAME_RELEASE fi GUESS=$UNAME_MACHINE-ibm-aix$IBM_REV ;; *:AIX:2:3) if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then set_cc_for_build sed 's/^ //' << EOF > "$dummy.c" #include main() { if (!__power_pc()) exit(1); puts("powerpc-ibm-aix3.2.5"); exit(0); } EOF if $CC_FOR_BUILD -o "$dummy" "$dummy.c" && SYSTEM_NAME=`"$dummy"` then GUESS=$SYSTEM_NAME else GUESS=rs6000-ibm-aix3.2.5 fi elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then GUESS=rs6000-ibm-aix3.2.4 else GUESS=rs6000-ibm-aix3.2 fi ;; *:AIX:*:[4567]) IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` if /usr/sbin/lsattr -El "$IBM_CPU_ID" | grep ' POWER' >/dev/null 2>&1; then IBM_ARCH=rs6000 else IBM_ARCH=powerpc fi if test -x /usr/bin/lslpp ; then IBM_REV=`/usr/bin/lslpp -Lqc bos.rte.libc | \ awk -F: '{ print $3 }' | sed s/[0-9]*$/0/` else IBM_REV=$UNAME_VERSION.$UNAME_RELEASE fi GUESS=$IBM_ARCH-ibm-aix$IBM_REV ;; *:AIX:*:*) GUESS=rs6000-ibm-aix ;; ibmrt:4.4BSD:*|romp-ibm:4.4BSD:*) GUESS=romp-ibm-bsd4.4 ;; ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and GUESS=romp-ibm-bsd$UNAME_RELEASE # 4.3 with uname added to ;; # report: romp-ibm BSD 4.3 *:BOSX:*:*) GUESS=rs6000-bull-bosx ;; DPX/2?00:B.O.S.:*:*) GUESS=m68k-bull-sysv3 ;; 9000/[34]??:4.3bsd:1.*:*) GUESS=m68k-hp-bsd ;; hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) GUESS=m68k-hp-bsd4.4 ;; 9000/[34678]??:HP-UX:*:*) HPUX_REV=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*.[0B]*//'` case $UNAME_MACHINE in 9000/31?) HP_ARCH=m68000 ;; 9000/[34]??) HP_ARCH=m68k ;; 9000/[678][0-9][0-9]) if test -x /usr/bin/getconf; then sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` case $sc_cpu_version in 523) HP_ARCH=hppa1.0 ;; # CPU_PA_RISC1_0 528) HP_ARCH=hppa1.1 ;; # CPU_PA_RISC1_1 532) # CPU_PA_RISC2_0 case $sc_kernel_bits in 32) HP_ARCH=hppa2.0n ;; 64) HP_ARCH=hppa2.0w ;; '') HP_ARCH=hppa2.0 ;; # HP-UX 10.20 esac ;; esac fi if test "$HP_ARCH" = ""; then set_cc_for_build sed 's/^ //' << EOF > "$dummy.c" #define _HPUX_SOURCE #include #include int main () { #if defined(_SC_KERNEL_BITS) long bits = sysconf(_SC_KERNEL_BITS); #endif long cpu = sysconf (_SC_CPU_VERSION); switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0"); break; case CPU_PA_RISC1_1: puts ("hppa1.1"); break; case CPU_PA_RISC2_0: #if defined(_SC_KERNEL_BITS) switch (bits) { case 64: puts ("hppa2.0w"); break; case 32: puts ("hppa2.0n"); break; default: puts ("hppa2.0"); break; } break; #else /* !defined(_SC_KERNEL_BITS) */ puts ("hppa2.0"); break; #endif default: puts ("hppa1.0"); break; } exit (0); } EOF (CCOPTS="" $CC_FOR_BUILD -o "$dummy" "$dummy.c" 2>/dev/null) && HP_ARCH=`"$dummy"` test -z "$HP_ARCH" && HP_ARCH=hppa fi ;; esac if test "$HP_ARCH" = hppa2.0w then set_cc_for_build # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler # generating 64-bit code. GNU and HP use different nomenclature: # # $ CC_FOR_BUILD=cc ./config.guess # => hppa2.0w-hp-hpux11.23 # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess # => hppa64-hp-hpux11.23 if echo __LP64__ | (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | grep -q __LP64__ then HP_ARCH=hppa2.0w else HP_ARCH=hppa64 fi fi GUESS=$HP_ARCH-hp-hpux$HPUX_REV ;; ia64:HP-UX:*:*) HPUX_REV=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*.[0B]*//'` GUESS=ia64-hp-hpux$HPUX_REV ;; 3050*:HI-UX:*:*) set_cc_for_build sed 's/^ //' << EOF > "$dummy.c" #include int main () { long cpu = sysconf (_SC_CPU_VERSION); /* The order matters, because CPU_IS_HP_MC68K erroneously returns true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct results, however. */ if (CPU_IS_PA_RISC (cpu)) { switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; default: puts ("hppa-hitachi-hiuxwe2"); break; } } else if (CPU_IS_HP_MC68K (cpu)) puts ("m68k-hitachi-hiuxwe2"); else puts ("unknown-hitachi-hiuxwe2"); exit (0); } EOF $CC_FOR_BUILD -o "$dummy" "$dummy.c" && SYSTEM_NAME=`"$dummy"` && { echo "$SYSTEM_NAME"; exit; } GUESS=unknown-hitachi-hiuxwe2 ;; 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:*) GUESS=hppa1.1-hp-bsd ;; 9000/8??:4.3bsd:*:*) GUESS=hppa1.0-hp-bsd ;; *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) GUESS=hppa1.0-hp-mpeix ;; hp7??:OSF1:*:* | hp8?[79]:OSF1:*:*) GUESS=hppa1.1-hp-osf ;; hp8??:OSF1:*:*) GUESS=hppa1.0-hp-osf ;; i*86:OSF1:*:*) if test -x /usr/sbin/sysversion ; then GUESS=$UNAME_MACHINE-unknown-osf1mk else GUESS=$UNAME_MACHINE-unknown-osf1 fi ;; parisc*:Lites*:*:*) GUESS=hppa1.1-hp-lites ;; C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) GUESS=c1-convex-bsd ;; C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi exit ;; C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) GUESS=c34-convex-bsd ;; C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) GUESS=c38-convex-bsd ;; C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) GUESS=c4-convex-bsd ;; CRAY*Y-MP:*:*:*) CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'` GUESS=ymp-cray-unicos$CRAY_REL ;; CRAY*[A-Z]90:*:*:*) echo "$UNAME_MACHINE"-cray-unicos"$UNAME_RELEASE" \ | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ -e 's/\.[^.]*$/.X/' exit ;; CRAY*TS:*:*:*) CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'` GUESS=t90-cray-unicos$CRAY_REL ;; CRAY*T3E:*:*:*) CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'` GUESS=alphaev5-cray-unicosmk$CRAY_REL ;; CRAY*SV1:*:*:*) CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'` GUESS=sv1-cray-unicos$CRAY_REL ;; *:UNICOS/mp:*:*) CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'` GUESS=craynv-cray-unicosmp$CRAY_REL ;; F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) FUJITSU_PROC=`uname -m | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz` FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'` FUJITSU_REL=`echo "$UNAME_RELEASE" | sed -e 's/ /_/'` GUESS=${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL} ;; 5000:UNIX_System_V:4.*:*) FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'` FUJITSU_REL=`echo "$UNAME_RELEASE" | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/ /_/'` GUESS=sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL} ;; i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) GUESS=$UNAME_MACHINE-pc-bsdi$UNAME_RELEASE ;; sparc*:BSD/OS:*:*) GUESS=sparc-unknown-bsdi$UNAME_RELEASE ;; *:BSD/OS:*:*) GUESS=$UNAME_MACHINE-unknown-bsdi$UNAME_RELEASE ;; arm:FreeBSD:*:*) UNAME_PROCESSOR=`uname -p` set_cc_for_build if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_PCS_VFP then FREEBSD_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'` GUESS=$UNAME_PROCESSOR-unknown-freebsd$FREEBSD_REL-gnueabi else FREEBSD_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'` GUESS=$UNAME_PROCESSOR-unknown-freebsd$FREEBSD_REL-gnueabihf fi ;; *:FreeBSD:*:*) UNAME_PROCESSOR=`/usr/bin/uname -p` case $UNAME_PROCESSOR in amd64) UNAME_PROCESSOR=x86_64 ;; i386) UNAME_PROCESSOR=i586 ;; esac FREEBSD_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'` GUESS=$UNAME_PROCESSOR-unknown-freebsd$FREEBSD_REL ;; i*:CYGWIN*:*) GUESS=$UNAME_MACHINE-pc-cygwin ;; *:MINGW64*:*) GUESS=$UNAME_MACHINE-pc-mingw64 ;; *:MINGW*:*) GUESS=$UNAME_MACHINE-pc-mingw32 ;; *:MSYS*:*) GUESS=$UNAME_MACHINE-pc-msys ;; i*:PW*:*) GUESS=$UNAME_MACHINE-pc-pw32 ;; *:SerenityOS:*:*) GUESS=$UNAME_MACHINE-pc-serenity ;; *:Interix*:*) case $UNAME_MACHINE in x86) GUESS=i586-pc-interix$UNAME_RELEASE ;; authenticamd | genuineintel | EM64T) GUESS=x86_64-unknown-interix$UNAME_RELEASE ;; IA64) GUESS=ia64-unknown-interix$UNAME_RELEASE ;; esac ;; i*:UWIN*:*) GUESS=$UNAME_MACHINE-pc-uwin ;; amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) GUESS=x86_64-pc-cygwin ;; prep*:SunOS:5.*:*) SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` GUESS=powerpcle-unknown-solaris2$SUN_REL ;; *:GNU:*:*) # the GNU system GNU_ARCH=`echo "$UNAME_MACHINE" | sed -e 's,[-/].*$,,'` GNU_REL=`echo "$UNAME_RELEASE" | sed -e 's,/.*$,,'` GUESS=$GNU_ARCH-unknown-$LIBC$GNU_REL ;; *:GNU/*:*:*) # other systems with GNU libc and userland GNU_SYS=`echo "$UNAME_SYSTEM" | sed 's,^[^/]*/,,' | tr "[:upper:]" "[:lower:]"` GNU_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'` GUESS=$UNAME_MACHINE-unknown-$GNU_SYS$GNU_REL-$LIBC ;; *:Minix:*:*) GUESS=$UNAME_MACHINE-unknown-minix ;; aarch64:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; aarch64_be:Linux:*:*) UNAME_MACHINE=aarch64_be GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; alpha:Linux:*:*) case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' /proc/cpuinfo 2>/dev/null` in EV5) UNAME_MACHINE=alphaev5 ;; EV56) UNAME_MACHINE=alphaev56 ;; PCA56) UNAME_MACHINE=alphapca56 ;; PCA57) UNAME_MACHINE=alphapca56 ;; EV6) UNAME_MACHINE=alphaev6 ;; EV67) UNAME_MACHINE=alphaev67 ;; EV68*) UNAME_MACHINE=alphaev68 ;; esac objdump --private-headers /bin/sh | grep -q ld.so.1 if test "$?" = 0 ; then LIBC=gnulibc1 ; fi GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; arc:Linux:*:* | arceb:Linux:*:* | arc32:Linux:*:* | arc64:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; arm*:Linux:*:*) set_cc_for_build if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_EABI__ then GUESS=$UNAME_MACHINE-unknown-linux-$LIBC else if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_PCS_VFP then GUESS=$UNAME_MACHINE-unknown-linux-${LIBC}eabi else GUESS=$UNAME_MACHINE-unknown-linux-${LIBC}eabihf fi fi ;; avr32*:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; cris:Linux:*:*) GUESS=$UNAME_MACHINE-axis-linux-$LIBC ;; crisv32:Linux:*:*) GUESS=$UNAME_MACHINE-axis-linux-$LIBC ;; e2k:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; frv:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; hexagon:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; i*86:Linux:*:*) GUESS=$UNAME_MACHINE-pc-linux-$LIBC ;; ia64:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; k1om:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; loongarch32:Linux:*:* | loongarch64:Linux:*:* | loongarchx32:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; m32r*:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; m68*:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; mips:Linux:*:* | mips64:Linux:*:*) set_cc_for_build IS_GLIBC=0 test x"${LIBC}" = xgnu && IS_GLIBC=1 sed 's/^ //' << EOF > "$dummy.c" #undef CPU #undef mips #undef mipsel #undef mips64 #undef mips64el #if ${IS_GLIBC} && defined(_ABI64) LIBCABI=gnuabi64 #else #if ${IS_GLIBC} && defined(_ABIN32) LIBCABI=gnuabin32 #else LIBCABI=${LIBC} #endif #endif #if ${IS_GLIBC} && defined(__mips64) && defined(__mips_isa_rev) && __mips_isa_rev>=6 CPU=mipsisa64r6 #else #if ${IS_GLIBC} && !defined(__mips64) && defined(__mips_isa_rev) && __mips_isa_rev>=6 CPU=mipsisa32r6 #else #if defined(__mips64) CPU=mips64 #else CPU=mips #endif #endif #endif #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) MIPS_ENDIAN=el #else #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) MIPS_ENDIAN= #else MIPS_ENDIAN= #endif #endif EOF cc_set_vars=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^CPU\|^MIPS_ENDIAN\|^LIBCABI'` eval "$cc_set_vars" test "x$CPU" != x && { echo "$CPU${MIPS_ENDIAN}-unknown-linux-$LIBCABI"; exit; } ;; mips64el:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; openrisc*:Linux:*:*) GUESS=or1k-unknown-linux-$LIBC ;; or32:Linux:*:* | or1k*:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; padre:Linux:*:*) GUESS=sparc-unknown-linux-$LIBC ;; parisc64:Linux:*:* | hppa64:Linux:*:*) GUESS=hppa64-unknown-linux-$LIBC ;; parisc:Linux:*:* | hppa:Linux:*:*) # Look for CPU level case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in PA7*) GUESS=hppa1.1-unknown-linux-$LIBC ;; PA8*) GUESS=hppa2.0-unknown-linux-$LIBC ;; *) GUESS=hppa-unknown-linux-$LIBC ;; esac ;; ppc64:Linux:*:*) GUESS=powerpc64-unknown-linux-$LIBC ;; ppc:Linux:*:*) GUESS=powerpc-unknown-linux-$LIBC ;; ppc64le:Linux:*:*) GUESS=powerpc64le-unknown-linux-$LIBC ;; ppcle:Linux:*:*) GUESS=powerpcle-unknown-linux-$LIBC ;; riscv32:Linux:*:* | riscv32be:Linux:*:* | riscv64:Linux:*:* | riscv64be:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; s390:Linux:*:* | s390x:Linux:*:*) GUESS=$UNAME_MACHINE-ibm-linux-$LIBC ;; sh64*:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; sh*:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; sparc:Linux:*:* | sparc64:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; tile*:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; vax:Linux:*:*) GUESS=$UNAME_MACHINE-dec-linux-$LIBC ;; x86_64:Linux:*:*) set_cc_for_build CPU=$UNAME_MACHINE LIBCABI=$LIBC if test "$CC_FOR_BUILD" != no_compiler_found; then ABI=64 sed 's/^ //' << EOF > "$dummy.c" #ifdef __i386__ ABI=x86 #else #ifdef __ILP32__ ABI=x32 #endif #endif EOF cc_set_abi=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^ABI' | sed 's, ,,g'` eval "$cc_set_abi" case $ABI in x86) CPU=i686 ;; x32) LIBCABI=${LIBC}x32 ;; esac fi GUESS=$CPU-pc-linux-$LIBCABI ;; xtensa*:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; i*86:DYNIX/ptx:4*:*) # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. # earlier versions are messed up and put the nodename in both # sysname and nodename. GUESS=i386-sequent-sysv4 ;; i*86:UNIX_SV:4.2MP:2.*) # Unixware is an offshoot of SVR4, but it has its own version # number series starting with 2... # I am not positive that other SVR4 systems won't match this, # I just have to hope. -- rms. # Use sysv4.2uw... so that sysv4* matches it. GUESS=$UNAME_MACHINE-pc-sysv4.2uw$UNAME_VERSION ;; i*86:OS/2:*:*) # If we were able to find `uname', then EMX Unix compatibility # is probably installed. GUESS=$UNAME_MACHINE-pc-os2-emx ;; i*86:XTS-300:*:STOP) GUESS=$UNAME_MACHINE-unknown-stop ;; i*86:atheos:*:*) GUESS=$UNAME_MACHINE-unknown-atheos ;; i*86:syllable:*:*) GUESS=$UNAME_MACHINE-pc-syllable ;; i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*) GUESS=i386-unknown-lynxos$UNAME_RELEASE ;; i*86:*DOS:*:*) GUESS=$UNAME_MACHINE-pc-msdosdjgpp ;; i*86:*:4.*:*) UNAME_REL=`echo "$UNAME_RELEASE" | sed 's/\/MP$//'` if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then GUESS=$UNAME_MACHINE-univel-sysv$UNAME_REL else GUESS=$UNAME_MACHINE-pc-sysv$UNAME_REL fi ;; i*86:*:5:[678]*) # UnixWare 7.x, OpenUNIX and OpenServer 6. case `/bin/uname -X | grep "^Machine"` in *486*) UNAME_MACHINE=i486 ;; *Pentium) UNAME_MACHINE=i586 ;; *Pent*|*Celeron) UNAME_MACHINE=i686 ;; esac GUESS=$UNAME_MACHINE-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} ;; i*86:*:3.2:*) if test -f /usr/options/cb.name; then UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ && UNAME_MACHINE=i586 (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ && UNAME_MACHINE=i686 (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ && UNAME_MACHINE=i686 GUESS=$UNAME_MACHINE-pc-sco$UNAME_REL else GUESS=$UNAME_MACHINE-pc-sysv32 fi ;; pc:*:*:*) # Left here for compatibility: # uname -m prints for DJGPP always 'pc', but it prints nothing about # the processor, so we play safe by assuming i586. # Note: whatever this is, it MUST be the same as what config.sub # prints for the "djgpp" host, or else GDB configure will decide that # this is a cross-build. GUESS=i586-pc-msdosdjgpp ;; Intel:Mach:3*:*) GUESS=i386-pc-mach3 ;; paragon:*:*:*) GUESS=i860-intel-osf1 ;; i860:*:4.*:*) # i860-SVR4 if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then GUESS=i860-stardent-sysv$UNAME_RELEASE # Stardent Vistra i860-SVR4 else # Add other i860-SVR4 vendors below as they are discovered. GUESS=i860-unknown-sysv$UNAME_RELEASE # Unknown i860-SVR4 fi ;; mini*:CTIX:SYS*5:*) # "miniframe" GUESS=m68010-convergent-sysv ;; mc68k:UNIX:SYSTEM5:3.51m) GUESS=m68k-convergent-sysv ;; M680?0:D-NIX:5.3:*) GUESS=m68k-diab-dnix ;; M68*:*:R3V[5678]*:*) test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) OS_REL='' test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4.3"$OS_REL"; exit; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && { echo i586-ncr-sysv4.3"$OS_REL"; exit; } ;; 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4; exit; } ;; NCR*:*:4.2:* | MPRAS*:*:4.2:*) OS_REL='.3' test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4.3"$OS_REL"; exit; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && { echo i586-ncr-sysv4.3"$OS_REL"; exit; } /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \ && { echo i586-ncr-sysv4.3"$OS_REL"; exit; } ;; m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) GUESS=m68k-unknown-lynxos$UNAME_RELEASE ;; mc68030:UNIX_System_V:4.*:*) GUESS=m68k-atari-sysv4 ;; TSUNAMI:LynxOS:2.*:*) GUESS=sparc-unknown-lynxos$UNAME_RELEASE ;; rs6000:LynxOS:2.*:*) GUESS=rs6000-unknown-lynxos$UNAME_RELEASE ;; PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*) GUESS=powerpc-unknown-lynxos$UNAME_RELEASE ;; SM[BE]S:UNIX_SV:*:*) GUESS=mips-dde-sysv$UNAME_RELEASE ;; RM*:ReliantUNIX-*:*:*) GUESS=mips-sni-sysv4 ;; RM*:SINIX-*:*:*) GUESS=mips-sni-sysv4 ;; *:SINIX-*:*:*) if uname -p 2>/dev/null >/dev/null ; then UNAME_MACHINE=`(uname -p) 2>/dev/null` GUESS=$UNAME_MACHINE-sni-sysv4 else GUESS=ns32k-sni-sysv fi ;; PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort # says GUESS=i586-unisys-sysv4 ;; *:UNIX_System_V:4*:FTX*) # From Gerald Hewes . # How about differentiating between stratus architectures? -djm GUESS=hppa1.1-stratus-sysv4 ;; *:*:*:FTX*) # From seanf@swdc.stratus.com. GUESS=i860-stratus-sysv4 ;; i*86:VOS:*:*) # From Paul.Green@stratus.com. GUESS=$UNAME_MACHINE-stratus-vos ;; *:VOS:*:*) # From Paul.Green@stratus.com. GUESS=hppa1.1-stratus-vos ;; mc68*:A/UX:*:*) GUESS=m68k-apple-aux$UNAME_RELEASE ;; news*:NEWS-OS:6*:*) GUESS=mips-sony-newsos6 ;; R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) if test -d /usr/nec; then GUESS=mips-nec-sysv$UNAME_RELEASE else GUESS=mips-unknown-sysv$UNAME_RELEASE fi ;; BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. GUESS=powerpc-be-beos ;; BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. GUESS=powerpc-apple-beos ;; BePC:BeOS:*:*) # BeOS running on Intel PC compatible. GUESS=i586-pc-beos ;; BePC:Haiku:*:*) # Haiku running on Intel PC compatible. GUESS=i586-pc-haiku ;; ppc:Haiku:*:*) # Haiku running on Apple PowerPC GUESS=powerpc-apple-haiku ;; *:Haiku:*:*) # Haiku modern gcc (not bound by BeOS compat) GUESS=$UNAME_MACHINE-unknown-haiku ;; SX-4:SUPER-UX:*:*) GUESS=sx4-nec-superux$UNAME_RELEASE ;; SX-5:SUPER-UX:*:*) GUESS=sx5-nec-superux$UNAME_RELEASE ;; SX-6:SUPER-UX:*:*) GUESS=sx6-nec-superux$UNAME_RELEASE ;; SX-7:SUPER-UX:*:*) GUESS=sx7-nec-superux$UNAME_RELEASE ;; SX-8:SUPER-UX:*:*) GUESS=sx8-nec-superux$UNAME_RELEASE ;; SX-8R:SUPER-UX:*:*) GUESS=sx8r-nec-superux$UNAME_RELEASE ;; SX-ACE:SUPER-UX:*:*) GUESS=sxace-nec-superux$UNAME_RELEASE ;; Power*:Rhapsody:*:*) GUESS=powerpc-apple-rhapsody$UNAME_RELEASE ;; *:Rhapsody:*:*) GUESS=$UNAME_MACHINE-apple-rhapsody$UNAME_RELEASE ;; arm64:Darwin:*:*) GUESS=aarch64-apple-darwin$UNAME_RELEASE ;; *:Darwin:*:*) UNAME_PROCESSOR=`uname -p` case $UNAME_PROCESSOR in unknown) UNAME_PROCESSOR=powerpc ;; esac if command -v xcode-select > /dev/null 2> /dev/null && \ ! xcode-select --print-path > /dev/null 2> /dev/null ; then # Avoid executing cc if there is no toolchain installed as # cc will be a stub that puts up a graphical alert # prompting the user to install developer tools. CC_FOR_BUILD=no_compiler_found else set_cc_for_build fi if test "$CC_FOR_BUILD" != no_compiler_found; then if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \ (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ grep IS_64BIT_ARCH >/dev/null then case $UNAME_PROCESSOR in i386) UNAME_PROCESSOR=x86_64 ;; powerpc) UNAME_PROCESSOR=powerpc64 ;; esac fi # On 10.4-10.6 one might compile for PowerPC via gcc -arch ppc if (echo '#ifdef __POWERPC__'; echo IS_PPC; echo '#endif') | \ (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ grep IS_PPC >/dev/null then UNAME_PROCESSOR=powerpc fi elif test "$UNAME_PROCESSOR" = i386 ; then # uname -m returns i386 or x86_64 UNAME_PROCESSOR=$UNAME_MACHINE fi GUESS=$UNAME_PROCESSOR-apple-darwin$UNAME_RELEASE ;; *:procnto*:*:* | *:QNX:[0123456789]*:*) UNAME_PROCESSOR=`uname -p` if test "$UNAME_PROCESSOR" = x86; then UNAME_PROCESSOR=i386 UNAME_MACHINE=pc fi GUESS=$UNAME_PROCESSOR-$UNAME_MACHINE-nto-qnx$UNAME_RELEASE ;; *:QNX:*:4*) GUESS=i386-pc-qnx ;; NEO-*:NONSTOP_KERNEL:*:*) GUESS=neo-tandem-nsk$UNAME_RELEASE ;; NSE-*:NONSTOP_KERNEL:*:*) GUESS=nse-tandem-nsk$UNAME_RELEASE ;; NSR-*:NONSTOP_KERNEL:*:*) GUESS=nsr-tandem-nsk$UNAME_RELEASE ;; NSV-*:NONSTOP_KERNEL:*:*) GUESS=nsv-tandem-nsk$UNAME_RELEASE ;; NSX-*:NONSTOP_KERNEL:*:*) GUESS=nsx-tandem-nsk$UNAME_RELEASE ;; *:NonStop-UX:*:*) GUESS=mips-compaq-nonstopux ;; BS2000:POSIX*:*:*) GUESS=bs2000-siemens-sysv ;; DS/*:UNIX_System_V:*:*) GUESS=$UNAME_MACHINE-$UNAME_SYSTEM-$UNAME_RELEASE ;; *:Plan9:*:*) # "uname -m" is not consistent, so use $cputype instead. 386 # is converted to i386 for consistency with other x86 # operating systems. if test "${cputype-}" = 386; then UNAME_MACHINE=i386 elif test "x${cputype-}" != x; then UNAME_MACHINE=$cputype fi GUESS=$UNAME_MACHINE-unknown-plan9 ;; *:TOPS-10:*:*) GUESS=pdp10-unknown-tops10 ;; *:TENEX:*:*) GUESS=pdp10-unknown-tenex ;; KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) GUESS=pdp10-dec-tops20 ;; XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) GUESS=pdp10-xkl-tops20 ;; *:TOPS-20:*:*) GUESS=pdp10-unknown-tops20 ;; *:ITS:*:*) GUESS=pdp10-unknown-its ;; SEI:*:*:SEIUX) GUESS=mips-sei-seiux$UNAME_RELEASE ;; *:DragonFly:*:*) DRAGONFLY_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'` GUESS=$UNAME_MACHINE-unknown-dragonfly$DRAGONFLY_REL ;; *:*VMS:*:*) UNAME_MACHINE=`(uname -p) 2>/dev/null` case $UNAME_MACHINE in A*) GUESS=alpha-dec-vms ;; I*) GUESS=ia64-dec-vms ;; V*) GUESS=vax-dec-vms ;; esac ;; *:XENIX:*:SysV) GUESS=i386-pc-xenix ;; i*86:skyos:*:*) SKYOS_REL=`echo "$UNAME_RELEASE" | sed -e 's/ .*$//'` GUESS=$UNAME_MACHINE-pc-skyos$SKYOS_REL ;; i*86:rdos:*:*) GUESS=$UNAME_MACHINE-pc-rdos ;; i*86:Fiwix:*:*) GUESS=$UNAME_MACHINE-pc-fiwix ;; *:AROS:*:*) GUESS=$UNAME_MACHINE-unknown-aros ;; x86_64:VMkernel:*:*) GUESS=$UNAME_MACHINE-unknown-esx ;; amd64:Isilon\ OneFS:*:*) GUESS=x86_64-unknown-onefs ;; *:Unleashed:*:*) GUESS=$UNAME_MACHINE-unknown-unleashed$UNAME_RELEASE ;; esac # Do we have a guess based on uname results? if test "x$GUESS" != x; then echo "$GUESS" exit fi # No uname command or uname output not recognized. set_cc_for_build cat > "$dummy.c" < #include #endif #if defined(ultrix) || defined(_ultrix) || defined(__ultrix) || defined(__ultrix__) #if defined (vax) || defined (__vax) || defined (__vax__) || defined(mips) || defined(__mips) || defined(__mips__) || defined(MIPS) || defined(__MIPS__) #include #if defined(_SIZE_T_) || defined(SIGLOST) #include #endif #endif #endif main () { #if defined (sony) #if defined (MIPSEB) /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, I don't know.... */ printf ("mips-sony-bsd\n"); exit (0); #else #include printf ("m68k-sony-newsos%s\n", #ifdef NEWSOS4 "4" #else "" #endif ); exit (0); #endif #endif #if defined (NeXT) #if !defined (__ARCHITECTURE__) #define __ARCHITECTURE__ "m68k" #endif int version; version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; if (version < 4) printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); else printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); exit (0); #endif #if defined (MULTIMAX) || defined (n16) #if defined (UMAXV) printf ("ns32k-encore-sysv\n"); exit (0); #else #if defined (CMU) printf ("ns32k-encore-mach\n"); exit (0); #else printf ("ns32k-encore-bsd\n"); exit (0); #endif #endif #endif #if defined (__386BSD__) printf ("i386-pc-bsd\n"); exit (0); #endif #if defined (sequent) #if defined (i386) printf ("i386-sequent-dynix\n"); exit (0); #endif #if defined (ns32000) printf ("ns32k-sequent-dynix\n"); exit (0); #endif #endif #if defined (_SEQUENT_) struct utsname un; uname(&un); if (strncmp(un.version, "V2", 2) == 0) { printf ("i386-sequent-ptx2\n"); exit (0); } if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ printf ("i386-sequent-ptx1\n"); exit (0); } printf ("i386-sequent-ptx\n"); exit (0); #endif #if defined (vax) #if !defined (ultrix) #include #if defined (BSD) #if BSD == 43 printf ("vax-dec-bsd4.3\n"); exit (0); #else #if BSD == 199006 printf ("vax-dec-bsd4.3reno\n"); exit (0); #else printf ("vax-dec-bsd\n"); exit (0); #endif #endif #else printf ("vax-dec-bsd\n"); exit (0); #endif #else #if defined(_SIZE_T_) || defined(SIGLOST) struct utsname un; uname (&un); printf ("vax-dec-ultrix%s\n", un.release); exit (0); #else printf ("vax-dec-ultrix\n"); exit (0); #endif #endif #endif #if defined(ultrix) || defined(_ultrix) || defined(__ultrix) || defined(__ultrix__) #if defined(mips) || defined(__mips) || defined(__mips__) || defined(MIPS) || defined(__MIPS__) #if defined(_SIZE_T_) || defined(SIGLOST) struct utsname *un; uname (&un); printf ("mips-dec-ultrix%s\n", un.release); exit (0); #else printf ("mips-dec-ultrix\n"); exit (0); #endif #endif #endif #if defined (alliant) && defined (i860) printf ("i860-alliant-bsd\n"); exit (0); #endif exit (1); } EOF $CC_FOR_BUILD -o "$dummy" "$dummy.c" 2>/dev/null && SYSTEM_NAME=`"$dummy"` && { echo "$SYSTEM_NAME"; exit; } # Apollos put the system type in the environment. test -d /usr/apollo && { echo "$ISP-apollo-$SYSTYPE"; exit; } echo "$0: unable to guess system type" >&2 case $UNAME_MACHINE:$UNAME_SYSTEM in mips:Linux | mips64:Linux) # If we got here on MIPS GNU/Linux, output extra information. cat >&2 <&2 <&2 </dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` /bin/uname -X = `(/bin/uname -X) 2>/dev/null` hostinfo = `(hostinfo) 2>/dev/null` /bin/universe = `(/bin/universe) 2>/dev/null` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` /bin/arch = `(/bin/arch) 2>/dev/null` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` UNAME_MACHINE = "$UNAME_MACHINE" UNAME_RELEASE = "$UNAME_RELEASE" UNAME_SYSTEM = "$UNAME_SYSTEM" UNAME_VERSION = "$UNAME_VERSION" EOF fi exit 1 # Local variables: # eval: (add-hook 'before-save-hook 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: librecast/libs/libmld/config.sub000066400000000000000000001051161502456746400172230ustar00rootroot00000000000000#! /bin/sh # Configuration validation subroutine script. # Copyright 1992-2022 Free Software Foundation, Inc. # shellcheck disable=SC2006,SC2268 # see below for rationale timestamp='2022-01-03' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 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 . # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that # program. This Exception is an additional permission under section 7 # of the GNU General Public License, version 3 ("GPLv3"). # Please send patches to . # # Configuration subroutine to validate and canonicalize a configuration type. # Supply the specified configuration type as an argument. # If it is invalid, we print an error message on stderr and exit with code 1. # Otherwise, we print the canonical config type on stdout and succeed. # You can get the latest version of this script from: # https://git.savannah.gnu.org/cgit/config.git/plain/config.sub # This file is supposed to be the same for all GNU packages # and recognize all the CPU types, system types and aliases # that are meaningful with *any* GNU software. # Each package is responsible for reporting which valid configurations # it does not support. The user should be able to distinguish # a failure to support a valid configuration from a meaningless # configuration. # The goal of this file is to map all the various variations of a given # machine specification into a single specification in the form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM # or in some cases, the newer four-part form: # CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM # It is wrong to echo any other type of specification. # The "shellcheck disable" line above the timestamp inhibits complaints # about features and limitations of the classic Bourne shell that were # superseded or lifted in POSIX. However, this script identifies a wide # variety of pre-POSIX systems that do not have POSIX shells at all, and # even some reasonably current systems (Solaris 10 as case-in-point) still # have a pre-POSIX /bin/sh. me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] CPU-MFR-OPSYS or ALIAS Canonicalize a configuration name. Options: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.sub ($timestamp) Copyright 1992-2022 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit ;; --version | -v ) echo "$version" ; exit ;; --help | --h* | -h ) echo "$usage"; exit ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" >&2 exit 1 ;; *local*) # First pass through any local machine types. echo "$1" exit ;; * ) break ;; esac done case $# in 0) echo "$me: missing argument$help" >&2 exit 1;; 1) ;; *) echo "$me: too many arguments$help" >&2 exit 1;; esac # Split fields of configuration type # shellcheck disable=SC2162 saved_IFS=$IFS IFS="-" read field1 field2 field3 field4 <&2 exit 1 ;; *-*-*-*) basic_machine=$field1-$field2 basic_os=$field3-$field4 ;; *-*-*) # Ambiguous whether COMPANY is present, or skipped and KERNEL-OS is two # parts maybe_os=$field2-$field3 case $maybe_os in nto-qnx* | linux-* | uclinux-uclibc* \ | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* \ | netbsd*-eabi* | kopensolaris*-gnu* | cloudabi*-eabi* \ | storm-chaos* | os2-emx* | rtmk-nova*) basic_machine=$field1 basic_os=$maybe_os ;; android-linux) basic_machine=$field1-unknown basic_os=linux-android ;; *) basic_machine=$field1-$field2 basic_os=$field3 ;; esac ;; *-*) # A lone config we happen to match not fitting any pattern case $field1-$field2 in decstation-3100) basic_machine=mips-dec basic_os= ;; *-*) # Second component is usually, but not always the OS case $field2 in # Prevent following clause from handling this valid os sun*os*) basic_machine=$field1 basic_os=$field2 ;; zephyr*) basic_machine=$field1-unknown basic_os=$field2 ;; # Manufacturers dec* | mips* | sequent* | encore* | pc533* | sgi* | sony* \ | att* | 7300* | 3300* | delta* | motorola* | sun[234]* \ | unicom* | ibm* | next | hp | isi* | apollo | altos* \ | convergent* | ncr* | news | 32* | 3600* | 3100* \ | hitachi* | c[123]* | convex* | sun | crds | omron* | dg \ | ultra | tti* | harris | dolphin | highlevel | gould \ | cbm | ns | masscomp | apple | axis | knuth | cray \ | microblaze* | sim | cisco \ | oki | wec | wrs | winbond) basic_machine=$field1-$field2 basic_os= ;; *) basic_machine=$field1 basic_os=$field2 ;; esac ;; esac ;; *) # Convert single-component short-hands not valid as part of # multi-component configurations. case $field1 in 386bsd) basic_machine=i386-pc basic_os=bsd ;; a29khif) basic_machine=a29k-amd basic_os=udi ;; adobe68k) basic_machine=m68010-adobe basic_os=scout ;; alliant) basic_machine=fx80-alliant basic_os= ;; altos | altos3068) basic_machine=m68k-altos basic_os= ;; am29k) basic_machine=a29k-none basic_os=bsd ;; amdahl) basic_machine=580-amdahl basic_os=sysv ;; amiga) basic_machine=m68k-unknown basic_os= ;; amigaos | amigados) basic_machine=m68k-unknown basic_os=amigaos ;; amigaunix | amix) basic_machine=m68k-unknown basic_os=sysv4 ;; apollo68) basic_machine=m68k-apollo basic_os=sysv ;; apollo68bsd) basic_machine=m68k-apollo basic_os=bsd ;; aros) basic_machine=i386-pc basic_os=aros ;; aux) basic_machine=m68k-apple basic_os=aux ;; balance) basic_machine=ns32k-sequent basic_os=dynix ;; blackfin) basic_machine=bfin-unknown basic_os=linux ;; cegcc) basic_machine=arm-unknown basic_os=cegcc ;; convex-c1) basic_machine=c1-convex basic_os=bsd ;; convex-c2) basic_machine=c2-convex basic_os=bsd ;; convex-c32) basic_machine=c32-convex basic_os=bsd ;; convex-c34) basic_machine=c34-convex basic_os=bsd ;; convex-c38) basic_machine=c38-convex basic_os=bsd ;; cray) basic_machine=j90-cray basic_os=unicos ;; crds | unos) basic_machine=m68k-crds basic_os= ;; da30) basic_machine=m68k-da30 basic_os= ;; decstation | pmax | pmin | dec3100 | decstatn) basic_machine=mips-dec basic_os= ;; delta88) basic_machine=m88k-motorola basic_os=sysv3 ;; dicos) basic_machine=i686-pc basic_os=dicos ;; djgpp) basic_machine=i586-pc basic_os=msdosdjgpp ;; ebmon29k) basic_machine=a29k-amd basic_os=ebmon ;; es1800 | OSE68k | ose68k | ose | OSE) basic_machine=m68k-ericsson basic_os=ose ;; gmicro) basic_machine=tron-gmicro basic_os=sysv ;; go32) basic_machine=i386-pc basic_os=go32 ;; h8300hms) basic_machine=h8300-hitachi basic_os=hms ;; h8300xray) basic_machine=h8300-hitachi basic_os=xray ;; h8500hms) basic_machine=h8500-hitachi basic_os=hms ;; harris) basic_machine=m88k-harris basic_os=sysv3 ;; hp300 | hp300hpux) basic_machine=m68k-hp basic_os=hpux ;; hp300bsd) basic_machine=m68k-hp basic_os=bsd ;; hppaosf) basic_machine=hppa1.1-hp basic_os=osf ;; hppro) basic_machine=hppa1.1-hp basic_os=proelf ;; i386mach) basic_machine=i386-mach basic_os=mach ;; isi68 | isi) basic_machine=m68k-isi basic_os=sysv ;; m68knommu) basic_machine=m68k-unknown basic_os=linux ;; magnum | m3230) basic_machine=mips-mips basic_os=sysv ;; merlin) basic_machine=ns32k-utek basic_os=sysv ;; mingw64) basic_machine=x86_64-pc basic_os=mingw64 ;; mingw32) basic_machine=i686-pc basic_os=mingw32 ;; mingw32ce) basic_machine=arm-unknown basic_os=mingw32ce ;; monitor) basic_machine=m68k-rom68k basic_os=coff ;; morphos) basic_machine=powerpc-unknown basic_os=morphos ;; moxiebox) basic_machine=moxie-unknown basic_os=moxiebox ;; msdos) basic_machine=i386-pc basic_os=msdos ;; msys) basic_machine=i686-pc basic_os=msys ;; mvs) basic_machine=i370-ibm basic_os=mvs ;; nacl) basic_machine=le32-unknown basic_os=nacl ;; ncr3000) basic_machine=i486-ncr basic_os=sysv4 ;; netbsd386) basic_machine=i386-pc basic_os=netbsd ;; netwinder) basic_machine=armv4l-rebel basic_os=linux ;; news | news700 | news800 | news900) basic_machine=m68k-sony basic_os=newsos ;; news1000) basic_machine=m68030-sony basic_os=newsos ;; necv70) basic_machine=v70-nec basic_os=sysv ;; nh3000) basic_machine=m68k-harris basic_os=cxux ;; nh[45]000) basic_machine=m88k-harris basic_os=cxux ;; nindy960) basic_machine=i960-intel basic_os=nindy ;; mon960) basic_machine=i960-intel basic_os=mon960 ;; nonstopux) basic_machine=mips-compaq basic_os=nonstopux ;; os400) basic_machine=powerpc-ibm basic_os=os400 ;; OSE68000 | ose68000) basic_machine=m68000-ericsson basic_os=ose ;; os68k) basic_machine=m68k-none basic_os=os68k ;; paragon) basic_machine=i860-intel basic_os=osf ;; parisc) basic_machine=hppa-unknown basic_os=linux ;; psp) basic_machine=mipsallegrexel-sony basic_os=psp ;; pw32) basic_machine=i586-unknown basic_os=pw32 ;; rdos | rdos64) basic_machine=x86_64-pc basic_os=rdos ;; rdos32) basic_machine=i386-pc basic_os=rdos ;; rom68k) basic_machine=m68k-rom68k basic_os=coff ;; sa29200) basic_machine=a29k-amd basic_os=udi ;; sei) basic_machine=mips-sei basic_os=seiux ;; sequent) basic_machine=i386-sequent basic_os= ;; sps7) basic_machine=m68k-bull basic_os=sysv2 ;; st2000) basic_machine=m68k-tandem basic_os= ;; stratus) basic_machine=i860-stratus basic_os=sysv4 ;; sun2) basic_machine=m68000-sun basic_os= ;; sun2os3) basic_machine=m68000-sun basic_os=sunos3 ;; sun2os4) basic_machine=m68000-sun basic_os=sunos4 ;; sun3) basic_machine=m68k-sun basic_os= ;; sun3os3) basic_machine=m68k-sun basic_os=sunos3 ;; sun3os4) basic_machine=m68k-sun basic_os=sunos4 ;; sun4) basic_machine=sparc-sun basic_os= ;; sun4os3) basic_machine=sparc-sun basic_os=sunos3 ;; sun4os4) basic_machine=sparc-sun basic_os=sunos4 ;; sun4sol2) basic_machine=sparc-sun basic_os=solaris2 ;; sun386 | sun386i | roadrunner) basic_machine=i386-sun basic_os= ;; sv1) basic_machine=sv1-cray basic_os=unicos ;; symmetry) basic_machine=i386-sequent basic_os=dynix ;; t3e) basic_machine=alphaev5-cray basic_os=unicos ;; t90) basic_machine=t90-cray basic_os=unicos ;; toad1) basic_machine=pdp10-xkl basic_os=tops20 ;; tpf) basic_machine=s390x-ibm basic_os=tpf ;; udi29k) basic_machine=a29k-amd basic_os=udi ;; ultra3) basic_machine=a29k-nyu basic_os=sym1 ;; v810 | necv810) basic_machine=v810-nec basic_os=none ;; vaxv) basic_machine=vax-dec basic_os=sysv ;; vms) basic_machine=vax-dec basic_os=vms ;; vsta) basic_machine=i386-pc basic_os=vsta ;; vxworks960) basic_machine=i960-wrs basic_os=vxworks ;; vxworks68) basic_machine=m68k-wrs basic_os=vxworks ;; vxworks29k) basic_machine=a29k-wrs basic_os=vxworks ;; xbox) basic_machine=i686-pc basic_os=mingw32 ;; ymp) basic_machine=ymp-cray basic_os=unicos ;; *) basic_machine=$1 basic_os= ;; esac ;; esac # Decode 1-component or ad-hoc basic machines case $basic_machine in # Here we handle the default manufacturer of certain CPU types. It is in # some cases the only manufacturer, in others, it is the most popular. w89k) cpu=hppa1.1 vendor=winbond ;; op50n) cpu=hppa1.1 vendor=oki ;; op60c) cpu=hppa1.1 vendor=oki ;; ibm*) cpu=i370 vendor=ibm ;; orion105) cpu=clipper vendor=highlevel ;; mac | mpw | mac-mpw) cpu=m68k vendor=apple ;; pmac | pmac-mpw) cpu=powerpc vendor=apple ;; # Recognize the various machine names and aliases which stand # for a CPU type and a company and sometimes even an OS. 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) cpu=m68000 vendor=att ;; 3b*) cpu=we32k vendor=att ;; bluegene*) cpu=powerpc vendor=ibm basic_os=cnk ;; decsystem10* | dec10*) cpu=pdp10 vendor=dec basic_os=tops10 ;; decsystem20* | dec20*) cpu=pdp10 vendor=dec basic_os=tops20 ;; delta | 3300 | motorola-3300 | motorola-delta \ | 3300-motorola | delta-motorola) cpu=m68k vendor=motorola ;; dpx2*) cpu=m68k vendor=bull basic_os=sysv3 ;; encore | umax | mmax) cpu=ns32k vendor=encore ;; elxsi) cpu=elxsi vendor=elxsi basic_os=${basic_os:-bsd} ;; fx2800) cpu=i860 vendor=alliant ;; genix) cpu=ns32k vendor=ns ;; h3050r* | hiux*) cpu=hppa1.1 vendor=hitachi basic_os=hiuxwe2 ;; hp3k9[0-9][0-9] | hp9[0-9][0-9]) cpu=hppa1.0 vendor=hp ;; hp9k2[0-9][0-9] | hp9k31[0-9]) cpu=m68000 vendor=hp ;; hp9k3[2-9][0-9]) cpu=m68k vendor=hp ;; hp9k6[0-9][0-9] | hp6[0-9][0-9]) cpu=hppa1.0 vendor=hp ;; hp9k7[0-79][0-9] | hp7[0-79][0-9]) cpu=hppa1.1 vendor=hp ;; hp9k78[0-9] | hp78[0-9]) # FIXME: really hppa2.0-hp cpu=hppa1.1 vendor=hp ;; hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) # FIXME: really hppa2.0-hp cpu=hppa1.1 vendor=hp ;; hp9k8[0-9][13679] | hp8[0-9][13679]) cpu=hppa1.1 vendor=hp ;; hp9k8[0-9][0-9] | hp8[0-9][0-9]) cpu=hppa1.0 vendor=hp ;; i*86v32) cpu=`echo "$1" | sed -e 's/86.*/86/'` vendor=pc basic_os=sysv32 ;; i*86v4*) cpu=`echo "$1" | sed -e 's/86.*/86/'` vendor=pc basic_os=sysv4 ;; i*86v) cpu=`echo "$1" | sed -e 's/86.*/86/'` vendor=pc basic_os=sysv ;; i*86sol2) cpu=`echo "$1" | sed -e 's/86.*/86/'` vendor=pc basic_os=solaris2 ;; j90 | j90-cray) cpu=j90 vendor=cray basic_os=${basic_os:-unicos} ;; iris | iris4d) cpu=mips vendor=sgi case $basic_os in irix*) ;; *) basic_os=irix4 ;; esac ;; miniframe) cpu=m68000 vendor=convergent ;; *mint | mint[0-9]* | *MiNT | *MiNT[0-9]*) cpu=m68k vendor=atari basic_os=mint ;; news-3600 | risc-news) cpu=mips vendor=sony basic_os=newsos ;; next | m*-next) cpu=m68k vendor=next case $basic_os in openstep*) ;; nextstep*) ;; ns2*) basic_os=nextstep2 ;; *) basic_os=nextstep3 ;; esac ;; np1) cpu=np1 vendor=gould ;; op50n-* | op60c-*) cpu=hppa1.1 vendor=oki basic_os=proelf ;; pa-hitachi) cpu=hppa1.1 vendor=hitachi basic_os=hiuxwe2 ;; pbd) cpu=sparc vendor=tti ;; pbb) cpu=m68k vendor=tti ;; pc532) cpu=ns32k vendor=pc532 ;; pn) cpu=pn vendor=gould ;; power) cpu=power vendor=ibm ;; ps2) cpu=i386 vendor=ibm ;; rm[46]00) cpu=mips vendor=siemens ;; rtpc | rtpc-*) cpu=romp vendor=ibm ;; sde) cpu=mipsisa32 vendor=sde basic_os=${basic_os:-elf} ;; simso-wrs) cpu=sparclite vendor=wrs basic_os=vxworks ;; tower | tower-32) cpu=m68k vendor=ncr ;; vpp*|vx|vx-*) cpu=f301 vendor=fujitsu ;; w65) cpu=w65 vendor=wdc ;; w89k-*) cpu=hppa1.1 vendor=winbond basic_os=proelf ;; none) cpu=none vendor=none ;; leon|leon[3-9]) cpu=sparc vendor=$basic_machine ;; leon-*|leon[3-9]-*) cpu=sparc vendor=`echo "$basic_machine" | sed 's/-.*//'` ;; *-*) # shellcheck disable=SC2162 saved_IFS=$IFS IFS="-" read cpu vendor <&2 exit 1 ;; esac ;; esac # Here we canonicalize certain aliases for manufacturers. case $vendor in digital*) vendor=dec ;; commodore*) vendor=cbm ;; *) ;; esac # Decode manufacturer-specific aliases for certain operating systems. if test x$basic_os != x then # First recognize some ad-hoc cases, or perhaps split kernel-os, or else just # set os. case $basic_os in gnu/linux*) kernel=linux os=`echo "$basic_os" | sed -e 's|gnu/linux|gnu|'` ;; os2-emx) kernel=os2 os=`echo "$basic_os" | sed -e 's|os2-emx|emx|'` ;; nto-qnx*) kernel=nto os=`echo "$basic_os" | sed -e 's|nto-qnx|qnx|'` ;; *-*) # shellcheck disable=SC2162 saved_IFS=$IFS IFS="-" read kernel os <&2 exit 1 ;; esac # As a final step for OS-related things, validate the OS-kernel combination # (given a valid OS), if there is a kernel. case $kernel-$os in linux-gnu* | linux-dietlibc* | linux-android* | linux-newlib* \ | linux-musl* | linux-relibc* | linux-uclibc* ) ;; uclinux-uclibc* ) ;; -dietlibc* | -newlib* | -musl* | -relibc* | -uclibc* ) # These are just libc implementations, not actual OSes, and thus # require a kernel. echo "Invalid configuration \`$1': libc \`$os' needs explicit kernel." 1>&2 exit 1 ;; kfreebsd*-gnu* | kopensolaris*-gnu*) ;; vxworks-simlinux | vxworks-simwindows | vxworks-spe) ;; nto-qnx*) ;; os2-emx) ;; *-eabi* | *-gnueabi*) ;; -*) # Blank kernel with real OS is always fine. ;; *-*) echo "Invalid configuration \`$1': Kernel \`$kernel' not known to work with OS \`$os'." 1>&2 exit 1 ;; esac # Here we handle the case where we know the os, and the CPU type, but not the # manufacturer. We pick the logical manufacturer. case $vendor in unknown) case $cpu-$os in *-riscix*) vendor=acorn ;; *-sunos*) vendor=sun ;; *-cnk* | *-aix*) vendor=ibm ;; *-beos*) vendor=be ;; *-hpux*) vendor=hp ;; *-mpeix*) vendor=hp ;; *-hiux*) vendor=hitachi ;; *-unos*) vendor=crds ;; *-dgux*) vendor=dg ;; *-luna*) vendor=omron ;; *-genix*) vendor=ns ;; *-clix*) vendor=intergraph ;; *-mvs* | *-opened*) vendor=ibm ;; *-os400*) vendor=ibm ;; s390-* | s390x-*) vendor=ibm ;; *-ptx*) vendor=sequent ;; *-tpf*) vendor=ibm ;; *-vxsim* | *-vxworks* | *-windiss*) vendor=wrs ;; *-aux*) vendor=apple ;; *-hms*) vendor=hitachi ;; *-mpw* | *-macos*) vendor=apple ;; *-*mint | *-mint[0-9]* | *-*MiNT | *-MiNT[0-9]*) vendor=atari ;; *-vos*) vendor=stratus ;; esac ;; esac echo "$cpu-$vendor-${kernel:+$kernel-}$os" exit # Local variables: # eval: (add-hook 'before-save-hook 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: librecast/libs/libmld/configure000077500000000000000000005256621502456746400171660ustar00rootroot00000000000000#! /bin/sh # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.71 for mld 0.0.0. # # Report bugs to . # # # Copyright (C) 1992-1996, 1998-2017, 2020-2021 Free Software Foundation, # Inc. # # # This configure script is free software; the Free Software Foundation # gives unlimited permission to copy, distribute and modify it. # # Copyright (c) 2022-2024 Brett Sheffield # See COPYING for license details. # ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh as_nop=: if test ${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else $as_nop case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi # Reset variables that may have inherited troublesome values from # the environment. # IFS needs to be set, to space, tab, and newline, in precisely that order. # (If _AS_PATH_WALK were called with IFS unset, it would have the # side effect of setting IFS to empty, thus disabling word splitting.) # Quoting is to prevent editors from complaining about space-tab. as_nl=' ' export as_nl IFS=" "" $as_nl" PS1='$ ' PS2='> ' PS4='+ ' # Ensure predictable behavior from utilities with locale-dependent output. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # We cannot yet rely on "unset" to work, but we need these variables # to be unset--not just set to an empty or harmless value--now, to # avoid bugs in old shells (e.g. pre-3.0 UWIN ksh). This construct # also avoids known problems related to "unset" and subshell syntax # in other old shells (e.g. bash 2.01 and pdksh 5.2.14). for as_var in BASH_ENV ENV MAIL MAILPATH CDPATH do eval test \${$as_var+y} \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done # Ensure that fds 0, 1, and 2 are open. if (exec 3>&0) 2>/dev/null; then :; else exec 0&1) 2>/dev/null; then :; else exec 1>/dev/null; fi if (exec 3>&2) ; then :; else exec 2>/dev/null; fi # The user is always right. if ${PATH_SEPARATOR+false} :; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac test -r "$as_dir$0" && as_myself=$as_dir$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then printf "%s\n" "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Use a proper internal environment variable to ensure we don't fall # into an infinite loop, continuously re-executing ourselves. if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then _as_can_reexec=no; export _as_can_reexec; # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV case $- in # (((( *v*x* | *x*v* ) as_opts=-vx ;; *v* ) as_opts=-v ;; *x* ) as_opts=-x ;; * ) as_opts= ;; esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. printf "%s\n" "$0: could not re-execute with $CONFIG_SHELL" >&2 exit 255 fi # We don't want this to propagate to other subprocesses. { _as_can_reexec=; unset _as_can_reexec;} if test "x$CONFIG_SHELL" = x; then as_bourne_compatible="as_nop=: if test \${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which # is contrary to our usage. Disable this feature. alias -g '\${1+\"\$@\"}'='\"\$@\"' setopt NO_GLOB_SUBST else \$as_nop case \`(set -o) 2>/dev/null\` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi " as_required="as_fn_return () { (exit \$1); } as_fn_success () { as_fn_return 0; } as_fn_failure () { as_fn_return 1; } as_fn_ret_success () { return 0; } as_fn_ret_failure () { return 1; } exitcode=0 as_fn_success || { exitcode=1; echo as_fn_success failed.; } as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } if ( set x; as_fn_ret_success y && test x = \"\$1\" ) then : else \$as_nop exitcode=1; echo positional parameters were not saved. fi test x\$exitcode = x0 || exit 1 blah=\$(echo \$(echo blah)) test x\"\$blah\" = xblah || exit 1 test -x / || exit 1" as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1" if (eval "$as_required") 2>/dev/null then : as_have_required=yes else $as_nop as_have_required=no fi if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null then : else $as_nop as_save_IFS=$IFS; IFS=$PATH_SEPARATOR as_found=false for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac as_found=: case $as_dir in #( /*) for as_base in sh bash ksh sh5; do # Try only shells that exist, to save several forks. as_shell=$as_dir$as_base if { test -f "$as_shell" || test -f "$as_shell.exe"; } && as_run=a "$as_shell" -c "$as_bourne_compatible""$as_required" 2>/dev/null then : CONFIG_SHELL=$as_shell as_have_required=yes if as_run=a "$as_shell" -c "$as_bourne_compatible""$as_suggested" 2>/dev/null then : break 2 fi fi done;; esac as_found=false done IFS=$as_save_IFS if $as_found then : else $as_nop if { test -f "$SHELL" || test -f "$SHELL.exe"; } && as_run=a "$SHELL" -c "$as_bourne_compatible""$as_required" 2>/dev/null then : CONFIG_SHELL=$SHELL as_have_required=yes fi fi if test "x$CONFIG_SHELL" != x then : export CONFIG_SHELL # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV case $- in # (((( *v*x* | *x*v* ) as_opts=-vx ;; *v* ) as_opts=-v ;; *x* ) as_opts=-x ;; * ) as_opts= ;; esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. printf "%s\n" "$0: could not re-execute with $CONFIG_SHELL" >&2 exit 255 fi if test x$as_have_required = xno then : printf "%s\n" "$0: This script requires a shell more modern than all" printf "%s\n" "$0: the shells that I found on your system." if test ${ZSH_VERSION+y} ; then printf "%s\n" "$0: In particular, zsh $ZSH_VERSION has bugs and should" printf "%s\n" "$0: be upgraded to zsh 4.3.4 or later." else printf "%s\n" "$0: Please tell bug-autoconf@gnu.org and bugs@librecast.net $0: about your system, including any error possibly output $0: before this message. Then install a modern shell, or $0: manually run the script under such a shell if you do $0: have one." fi exit 1 fi fi fi SHELL=${CONFIG_SHELL-/bin/sh} export SHELL # Unset more variables known to interfere with behavior of common tools. CLICOLOR_FORCE= GREP_OPTIONS= unset CLICOLOR_FORCE GREP_OPTIONS ## --------------------- ## ## M4sh Shell Functions. ## ## --------------------- ## # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_nop # --------- # Do nothing but, unlike ":", preserve the value of $?. as_fn_nop () { return $? } as_nop=as_fn_nop # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`printf "%s\n" "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || printf "%s\n" X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p # as_fn_executable_p FILE # ----------------------- # Test if FILE is an executable regular file. as_fn_executable_p () { test -f "$1" && test -x "$1" } # as_fn_executable_p # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null then : eval 'as_fn_append () { eval $1+=\$2 }' else $as_nop as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null then : eval 'as_fn_arith () { as_val=$(( $* )) }' else $as_nop as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith # as_fn_nop # --------- # Do nothing but, unlike ":", preserve the value of $?. as_fn_nop () { return $? } as_nop=as_fn_nop # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi printf "%s\n" "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || printf "%s\n" X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits as_lineno_1=$LINENO as_lineno_1a=$LINENO as_lineno_2=$LINENO as_lineno_2a=$LINENO eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) sed -n ' p /[$]LINENO/= ' <$as_myself | sed ' s/[$]LINENO.*/&-/ t lineno b :lineno N :loop s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ t loop s/-\n.*// ' >$as_me.lineno && chmod +x "$as_me.lineno" || { printf "%s\n" "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } # If we had to re-execute with $CONFIG_SHELL, we're ensured to have # already done that, so ensure we don't try to do so again and fall # in an infinite loop. This has already happened in practice. _as_can_reexec=no; export _as_can_reexec # Don't try to exec as it changes $[0], causing all sort of problems # (the dirname of $[0] is not the place where we might find the # original and so on. Autoconf is especially sensitive to this). . "./$as_me.lineno" # Exit status is that of the last command. exit } # Determine whether it's possible to make 'echo' print without a newline. # These variables are no longer used directly by Autoconf, but are AC_SUBSTed # for compatibility with existing Makefiles. ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac # For backward compatibility with old third-party macros, we provide # the shell variables $as_echo and $as_echo_n. New code should use # AS_ECHO(["message"]) and AS_ECHO_N(["message"]), respectively. as_echo='printf %s\n' as_echo_n='printf %s' rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -pR' fi else as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi as_test_x='test -x' as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" test -n "$DJDIR" || exec 7<&0 &1 # Name of the host. # hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, # so uname gets run too. ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` # # Initializations. # ac_default_prefix=/usr/local ac_clean_files= ac_config_libobj_dir=. LIBOBJS= cross_compiling=no subdirs= MFLAGS= MAKEFLAGS= # Identity of this package. PACKAGE_NAME='mld' PACKAGE_TARNAME='mld' PACKAGE_VERSION='0.0.0' PACKAGE_STRING='mld 0.0.0' PACKAGE_BUGREPORT='bugs@librecast.net' PACKAGE_URL='' ac_unique_file="src/" # Factoring default headers for most tests. ac_includes_default="\ #include #ifdef HAVE_STDIO_H # include #endif #ifdef HAVE_STDLIB_H # include #endif #ifdef HAVE_STRING_H # include #endif #ifdef HAVE_INTTYPES_H # include #endif #ifdef HAVE_STDINT_H # include #endif #ifdef HAVE_STRINGS_H # include #endif #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_STAT_H # include #endif #ifdef HAVE_UNISTD_H # include #endif" ac_header_c_list= ac_subst_vars='LTLIBOBJS LIBOBJS LIBRECAST_LDFLAGS LIBMLD LIBRECAST_CFLAGS MLD_BLOOM_FILTER VEC_O FALSE TESTRUNNER testrunner LN_S INSTALL_DATA INSTALL_SCRIPT INSTALL_PROGRAM ac_ct_CC CFLAGS CC OBJEXT EXEEXT ac_ct_CXX CPPFLAGS LDFLAGS CXXFLAGS CXX PACKAGE_ABIVERS target_alias host_alias build_alias LIBS ECHO_T ECHO_N ECHO_C DEFS mandir localedir libdir psdir pdfdir dvidir htmldir infodir docdir oldincludedir includedir runstatedir localstatedir sharedstatedir sysconfdir datadir datarootdir libexecdir sbindir bindir program_transform_name prefix exec_prefix PACKAGE_URL PACKAGE_BUGREPORT PACKAGE_STRING PACKAGE_VERSION PACKAGE_TARNAME PACKAGE_NAME PATH_SEPARATOR SHELL' ac_subst_files='' ac_user_opts=' enable_option_checking enable_bloom_filters ' ac_precious_vars='build_alias host_alias target_alias CXX CXXFLAGS LDFLAGS LIBS CPPFLAGS CCC CC CFLAGS' # Initialize some variables set by options. ac_init_help= ac_init_version=false ac_unrecognized_opts= ac_unrecognized_sep= # The variables have the same names as the options, with # dashes changed to underlines. cache_file=/dev/null exec_prefix=NONE no_create= no_recursion= prefix=NONE program_prefix=NONE program_suffix=NONE program_transform_name=s,x,x, silent= site= srcdir= verbose= x_includes=NONE x_libraries=NONE # Installation directory options. # These are left unexpanded so users can "make install exec_prefix=/foo" # and all the variables that are supposed to be based on exec_prefix # by default will actually change. # Use braces instead of parens because sh, perl, etc. also accept them. # (The list follows the same order as the GNU Coding Standards.) bindir='${exec_prefix}/bin' sbindir='${exec_prefix}/sbin' libexecdir='${exec_prefix}/libexec' datarootdir='${prefix}/share' datadir='${datarootdir}' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' runstatedir='${localstatedir}/run' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' infodir='${datarootdir}/info' htmldir='${docdir}' dvidir='${docdir}' pdfdir='${docdir}' psdir='${docdir}' libdir='${exec_prefix}/lib' localedir='${datarootdir}/locale' mandir='${datarootdir}/man' ac_prev= ac_dashdash= for ac_option do # If the previous option needs an argument, assign it. if test -n "$ac_prev"; then eval $ac_prev=\$ac_option ac_prev= continue fi case $ac_option in *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; *=) ac_optarg= ;; *) ac_optarg=yes ;; esac case $ac_dashdash$ac_option in --) ac_dashdash=yes ;; -bindir | --bindir | --bindi | --bind | --bin | --bi) ac_prev=bindir ;; -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) bindir=$ac_optarg ;; -build | --build | --buil | --bui | --bu) ac_prev=build_alias ;; -build=* | --build=* | --buil=* | --bui=* | --bu=*) build_alias=$ac_optarg ;; -cache-file | --cache-file | --cache-fil | --cache-fi \ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) ac_prev=cache_file ;; -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) cache_file=$ac_optarg ;; --config-cache | -C) cache_file=config.cache ;; -datadir | --datadir | --datadi | --datad) ac_prev=datadir ;; -datadir=* | --datadir=* | --datadi=* | --datad=*) datadir=$ac_optarg ;; -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ | --dataroo | --dataro | --datar) ac_prev=datarootdir ;; -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) datarootdir=$ac_optarg ;; -disable-* | --disable-*) ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: \`$ac_useropt'" ac_useropt_orig=$ac_useropt ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=no ;; -docdir | --docdir | --docdi | --doc | --do) ac_prev=docdir ;; -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) docdir=$ac_optarg ;; -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) ac_prev=dvidir ;; -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) dvidir=$ac_optarg ;; -enable-* | --enable-*) ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: \`$ac_useropt'" ac_useropt_orig=$ac_useropt ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=\$ac_optarg ;; -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ | --exec | --exe | --ex) ac_prev=exec_prefix ;; -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ | --exec=* | --exe=* | --ex=*) exec_prefix=$ac_optarg ;; -gas | --gas | --ga | --g) # Obsolete; use --with-gas. with_gas=yes ;; -help | --help | --hel | --he | -h) ac_init_help=long ;; -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) ac_init_help=recursive ;; -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) ac_init_help=short ;; -host | --host | --hos | --ho) ac_prev=host_alias ;; -host=* | --host=* | --hos=* | --ho=*) host_alias=$ac_optarg ;; -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) ac_prev=htmldir ;; -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ | --ht=*) htmldir=$ac_optarg ;; -includedir | --includedir | --includedi | --included | --include \ | --includ | --inclu | --incl | --inc) ac_prev=includedir ;; -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ | --includ=* | --inclu=* | --incl=* | --inc=*) includedir=$ac_optarg ;; -infodir | --infodir | --infodi | --infod | --info | --inf) ac_prev=infodir ;; -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) infodir=$ac_optarg ;; -libdir | --libdir | --libdi | --libd) ac_prev=libdir ;; -libdir=* | --libdir=* | --libdi=* | --libd=*) libdir=$ac_optarg ;; -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ | --libexe | --libex | --libe) ac_prev=libexecdir ;; -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ | --libexe=* | --libex=* | --libe=*) libexecdir=$ac_optarg ;; -localedir | --localedir | --localedi | --localed | --locale) ac_prev=localedir ;; -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) localedir=$ac_optarg ;; -localstatedir | --localstatedir | --localstatedi | --localstated \ | --localstate | --localstat | --localsta | --localst | --locals) ac_prev=localstatedir ;; -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) localstatedir=$ac_optarg ;; -mandir | --mandir | --mandi | --mand | --man | --ma | --m) ac_prev=mandir ;; -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) mandir=$ac_optarg ;; -nfp | --nfp | --nf) # Obsolete; use --without-fp. with_fp=no ;; -no-create | --no-create | --no-creat | --no-crea | --no-cre \ | --no-cr | --no-c | -n) no_create=yes ;; -no-recursion | --no-recursion | --no-recursio | --no-recursi \ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) no_recursion=yes ;; -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ | --oldin | --oldi | --old | --ol | --o) ac_prev=oldincludedir ;; -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) oldincludedir=$ac_optarg ;; -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) ac_prev=prefix ;; -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) prefix=$ac_optarg ;; -program-prefix | --program-prefix | --program-prefi | --program-pref \ | --program-pre | --program-pr | --program-p) ac_prev=program_prefix ;; -program-prefix=* | --program-prefix=* | --program-prefi=* \ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) program_prefix=$ac_optarg ;; -program-suffix | --program-suffix | --program-suffi | --program-suff \ | --program-suf | --program-su | --program-s) ac_prev=program_suffix ;; -program-suffix=* | --program-suffix=* | --program-suffi=* \ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) program_suffix=$ac_optarg ;; -program-transform-name | --program-transform-name \ | --program-transform-nam | --program-transform-na \ | --program-transform-n | --program-transform- \ | --program-transform | --program-transfor \ | --program-transfo | --program-transf \ | --program-trans | --program-tran \ | --progr-tra | --program-tr | --program-t) ac_prev=program_transform_name ;; -program-transform-name=* | --program-transform-name=* \ | --program-transform-nam=* | --program-transform-na=* \ | --program-transform-n=* | --program-transform-=* \ | --program-transform=* | --program-transfor=* \ | --program-transfo=* | --program-transf=* \ | --program-trans=* | --program-tran=* \ | --progr-tra=* | --program-tr=* | --program-t=*) program_transform_name=$ac_optarg ;; -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) ac_prev=pdfdir ;; -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) pdfdir=$ac_optarg ;; -psdir | --psdir | --psdi | --psd | --ps) ac_prev=psdir ;; -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) psdir=$ac_optarg ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) silent=yes ;; -runstatedir | --runstatedir | --runstatedi | --runstated \ | --runstate | --runstat | --runsta | --runst | --runs \ | --run | --ru | --r) ac_prev=runstatedir ;; -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \ | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \ | --run=* | --ru=* | --r=*) runstatedir=$ac_optarg ;; -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ | --sbi=* | --sb=*) sbindir=$ac_optarg ;; -sharedstatedir | --sharedstatedir | --sharedstatedi \ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ | --sharedst | --shareds | --shared | --share | --shar \ | --sha | --sh) ac_prev=sharedstatedir ;; -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ | --sha=* | --sh=*) sharedstatedir=$ac_optarg ;; -site | --site | --sit) ac_prev=site ;; -site=* | --site=* | --sit=*) site=$ac_optarg ;; -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) ac_prev=srcdir ;; -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) srcdir=$ac_optarg ;; -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ | --syscon | --sysco | --sysc | --sys | --sy) ac_prev=sysconfdir ;; -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) sysconfdir=$ac_optarg ;; -target | --target | --targe | --targ | --tar | --ta | --t) ac_prev=target_alias ;; -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) target_alias=$ac_optarg ;; -v | -verbose | --verbose | --verbos | --verbo | --verb) verbose=yes ;; -version | --version | --versio | --versi | --vers | -V) ac_init_version=: ;; -with-* | --with-*) ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: \`$ac_useropt'" ac_useropt_orig=$ac_useropt ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=\$ac_optarg ;; -without-* | --without-*) ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: \`$ac_useropt'" ac_useropt_orig=$ac_useropt ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=no ;; --x) # Obsolete; use --with-x. with_x=yes ;; -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ | --x-incl | --x-inc | --x-in | --x-i) ac_prev=x_includes ;; -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) x_includes=$ac_optarg ;; -x-libraries | --x-libraries | --x-librarie | --x-librari \ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) ac_prev=x_libraries ;; -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) x_libraries=$ac_optarg ;; -*) as_fn_error $? "unrecognized option: \`$ac_option' Try \`$0 --help' for more information" ;; *=*) ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` # Reject names that are not valid shell variable names. case $ac_envvar in #( '' | [0-9]* | *[!_$as_cr_alnum]* ) as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; esac eval $ac_envvar=\$ac_optarg export $ac_envvar ;; *) # FIXME: should be removed in autoconf 3.0. printf "%s\n" "$as_me: WARNING: you should use --build, --host, --target" >&2 expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && printf "%s\n" "$as_me: WARNING: invalid host type: $ac_option" >&2 : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" ;; esac done if test -n "$ac_prev"; then ac_option=--`echo $ac_prev | sed 's/_/-/g'` as_fn_error $? "missing argument to $ac_option" fi if test -n "$ac_unrecognized_opts"; then case $enable_option_checking in no) ;; fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; *) printf "%s\n" "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; esac fi # Check all directory arguments for consistency. for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ libdir localedir mandir runstatedir do eval ac_val=\$$ac_var # Remove trailing slashes. case $ac_val in */ ) ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` eval $ac_var=\$ac_val;; esac # Be sure to have absolute directory names. case $ac_val in [\\/$]* | ?:[\\/]* ) continue;; NONE | '' ) case $ac_var in *prefix ) continue;; esac;; esac as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" done # There might be people who depend on the old broken behavior: `$host' # used to hold the argument of --host etc. # FIXME: To remove some day. build=$build_alias host=$host_alias target=$target_alias # FIXME: To remove some day. if test "x$host_alias" != x; then if test "x$build_alias" = x; then cross_compiling=maybe elif test "x$build_alias" != "x$host_alias"; then cross_compiling=yes fi fi ac_tool_prefix= test -n "$host_alias" && ac_tool_prefix=$host_alias- test "$silent" = yes && exec 6>/dev/null ac_pwd=`pwd` && test -n "$ac_pwd" && ac_ls_di=`ls -di .` && ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || as_fn_error $? "working directory cannot be determined" test "X$ac_ls_di" = "X$ac_pwd_ls_di" || as_fn_error $? "pwd does not report name of working directory" # Find the source files, if location was not specified. if test -z "$srcdir"; then ac_srcdir_defaulted=yes # Try the directory containing this script, then the parent directory. ac_confdir=`$as_dirname -- "$as_myself" || $as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_myself" : 'X\(//\)[^/]' \| \ X"$as_myself" : 'X\(//\)$' \| \ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || printf "%s\n" X"$as_myself" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` srcdir=$ac_confdir if test ! -r "$srcdir/$ac_unique_file"; then srcdir=.. fi else ac_srcdir_defaulted=no fi if test ! -r "$srcdir/$ac_unique_file"; then test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" fi ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" ac_abs_confdir=`( cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" pwd)` # When building in place, set srcdir=. if test "$ac_abs_confdir" = "$ac_pwd"; then srcdir=. fi # Remove unnecessary trailing slashes from srcdir. # Double slashes in file names in object file debugging info # mess up M-x gdb in Emacs. case $srcdir in */) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; esac for ac_var in $ac_precious_vars; do eval ac_env_${ac_var}_set=\${${ac_var}+set} eval ac_env_${ac_var}_value=\$${ac_var} eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} eval ac_cv_env_${ac_var}_value=\$${ac_var} done # # Report the --help message. # if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF \`configure' configures mld 0.0.0 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... To assign environment variables (e.g., CC, CFLAGS...), specify them as VAR=VALUE. See below for descriptions of some of the useful variables. Defaults for the options are specified in brackets. Configuration: -h, --help display this help and exit --help=short display options specific to this package --help=recursive display the short help of all the included packages -V, --version display version information and exit -q, --quiet, --silent do not print \`checking ...' messages --cache-file=FILE cache test results in FILE [disabled] -C, --config-cache alias for \`--cache-file=config.cache' -n, --no-create do not create output files --srcdir=DIR find the sources in DIR [configure dir or \`..'] Installation directories: --prefix=PREFIX install architecture-independent files in PREFIX [$ac_default_prefix] --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX [PREFIX] By default, \`make install' will install all the files in \`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify an installation prefix other than \`$ac_default_prefix' using \`--prefix', for instance \`--prefix=\$HOME'. For better control, use the options below. Fine tuning of the installation directories: --bindir=DIR user executables [EPREFIX/bin] --sbindir=DIR system admin executables [EPREFIX/sbin] --libexecdir=DIR program executables [EPREFIX/libexec] --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] --datadir=DIR read-only architecture-independent data [DATAROOTDIR] --infodir=DIR info documentation [DATAROOTDIR/info] --localedir=DIR locale-dependent data [DATAROOTDIR/locale] --mandir=DIR man documentation [DATAROOTDIR/man] --docdir=DIR documentation root [DATAROOTDIR/doc/mld] --htmldir=DIR html documentation [DOCDIR] --dvidir=DIR dvi documentation [DOCDIR] --pdfdir=DIR pdf documentation [DOCDIR] --psdir=DIR ps documentation [DOCDIR] _ACEOF cat <<\_ACEOF _ACEOF fi if test -n "$ac_init_help"; then case $ac_init_help in short | recursive ) echo "Configuration of mld 0.0.0:";; esac cat <<\_ACEOF Optional Features: --disable-option-checking ignore unrecognized --enable/--with options --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) --enable-FEATURE[=ARG] include FEATURE [ARG=yes] --enable-bloom-filters Enable bloom filters Some influential environment variables: CXX C++ compiler command CXXFLAGS C++ compiler flags LDFLAGS linker flags, e.g. -L if you have libraries in a nonstandard directory LIBS libraries to pass to the linker, e.g. -l CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if you have headers in a nonstandard directory CC C compiler command CFLAGS C compiler flags Use these variables to override the choices made by `configure' or to help it to find libraries and programs with nonstandard names/locations. Report bugs to . _ACEOF ac_status=$? fi if test "$ac_init_help" = "recursive"; then # If there are subdirs, report their specific --help. for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue test -d "$ac_dir" || { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || continue ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`printf "%s\n" "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`printf "%s\n" "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix cd "$ac_dir" || { ac_status=$?; continue; } # Check for configure.gnu first; this name is used for a wrapper for # Metaconfig's "Configure" on case-insensitive file systems. if test -f "$ac_srcdir/configure.gnu"; then echo && $SHELL "$ac_srcdir/configure.gnu" --help=recursive elif test -f "$ac_srcdir/configure"; then echo && $SHELL "$ac_srcdir/configure" --help=recursive else printf "%s\n" "$as_me: WARNING: no configuration information is in $ac_dir" >&2 fi || ac_status=$? cd "$ac_pwd" || { ac_status=$?; break; } done fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF mld configure 0.0.0 generated by GNU Autoconf 2.71 Copyright (C) 2021 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. Copyright (c) 2022-2024 Brett Sheffield See COPYING for license details. _ACEOF exit fi ## ------------------------ ## ## Autoconf initialization. ## ## ------------------------ ## # ac_fn_cxx_try_compile LINENO # ---------------------------- # Try to compile conftest.$ac_ext, and return whether this succeeded. ac_fn_cxx_try_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext conftest.beam if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_cxx_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext then : ac_retval=0 else $as_nop printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_cxx_try_compile # ac_fn_c_try_compile LINENO # -------------------------- # Try to compile conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext conftest.beam if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext then : ac_retval=0 else $as_nop printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_compile # ac_fn_c_try_link LINENO # ----------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_link () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext conftest.beam conftest$ac_exeext if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_link") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || test -x conftest$ac_exeext } then : ac_retval=0 else $as_nop printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would # interfere with the next link command; also delete a directory that is # left behind by Apple's compiler. We do this before executing the actions. rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_link # ac_fn_c_check_func LINENO FUNC VAR # ---------------------------------- # Tests whether FUNC exists, setting the cache variable VAR accordingly ac_fn_c_check_func () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 printf %s "checking for $2... " >&6; } if eval test \${$3+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Define $2 to an innocuous variant, in case declares $2. For example, HP-UX 11i declares gettimeofday. */ #define $2 innocuous_$2 /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $2 (void); below. */ #include #undef $2 /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char $2 (void); /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined __stub_$2 || defined __stub___$2 choke me #endif int main (void) { return $2 (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : eval "$3=yes" else $as_nop eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext fi eval ac_res=\$$3 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 printf "%s\n" "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_func # ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES # ------------------------------------------------------- # Tests whether HEADER exists and can be compiled using the include files in # INCLUDES, setting the cache variable VAR accordingly. ac_fn_c_check_header_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 printf %s "checking for $2... " >&6; } if eval test \${$3+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> _ACEOF if ac_fn_c_try_compile "$LINENO" then : eval "$3=yes" else $as_nop eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi eval ac_res=\$$3 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 printf "%s\n" "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_header_compile # ac_fn_c_check_type LINENO TYPE VAR INCLUDES # ------------------------------------------- # Tests whether TYPE exists after having included INCLUDES, setting cache # variable VAR accordingly. ac_fn_c_check_type () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 printf %s "checking for $2... " >&6; } if eval test \${$3+y} then : printf %s "(cached) " >&6 else $as_nop eval "$3=no" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main (void) { if (sizeof ($2)) return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main (void) { if (sizeof (($2))) return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : else $as_nop eval "$3=yes" fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi eval ac_res=\$$3 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 printf "%s\n" "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_type # ac_fn_c_find_uintX_t LINENO BITS VAR # ------------------------------------ # Finds an unsigned integer type with width BITS, setting cache variable VAR # accordingly. ac_fn_c_find_uintX_t () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for uint$2_t" >&5 printf %s "checking for uint$2_t... " >&6; } if eval test \${$3+y} then : printf %s "(cached) " >&6 else $as_nop eval "$3=no" # Order is important - never check a type that is potentially smaller # than half of the expected target width. for ac_type in uint$2_t 'unsigned int' 'unsigned long int' \ 'unsigned long long int' 'unsigned short int' 'unsigned char'; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default int main (void) { static int test_array [1 - 2 * !((($ac_type) -1 >> ($2 / 2 - 1)) >> ($2 / 2 - 1) == 3)]; test_array [0] = 0; return test_array [0]; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : case $ac_type in #( uint$2_t) : eval "$3=yes" ;; #( *) : eval "$3=\$ac_type" ;; esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext if eval test \"x\$"$3"\" = x"no" then : else $as_nop break fi done fi eval ac_res=\$$3 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 printf "%s\n" "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_find_uintX_t ac_configure_args_raw= for ac_arg do case $ac_arg in *\'*) ac_arg=`printf "%s\n" "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac as_fn_append ac_configure_args_raw " '$ac_arg'" done case $ac_configure_args_raw in *$as_nl*) ac_safe_unquote= ;; *) ac_unsafe_z='|&;<>()$`\\"*?[ '' ' # This string ends in space, tab. ac_unsafe_a="$ac_unsafe_z#~" ac_safe_unquote="s/ '\\([^$ac_unsafe_a][^$ac_unsafe_z]*\\)'/ \\1/g" ac_configure_args_raw=` printf "%s\n" "$ac_configure_args_raw" | sed "$ac_safe_unquote"`;; esac cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. It was created by mld $as_me 0.0.0, which was generated by GNU Autoconf 2.71. Invocation command line was $ $0$ac_configure_args_raw _ACEOF exec 5>>config.log { cat <<_ASUNAME ## --------- ## ## Platform. ## ## --------- ## hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` /bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` /bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` /usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` /bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` /bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` _ASUNAME as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac printf "%s\n" "PATH: $as_dir" done IFS=$as_save_IFS } >&5 cat >&5 <<_ACEOF ## ----------- ## ## Core tests. ## ## ----------- ## _ACEOF # Keep a trace of the command line. # Strip out --no-create and --no-recursion so they do not pile up. # Strip out --silent because we don't want to record it for future runs. # Also quote any args containing shell meta-characters. # Make two passes to allow for proper duplicate-argument suppression. ac_configure_args= ac_configure_args0= ac_configure_args1= ac_must_keep_next=false for ac_pass in 1 2 do for ac_arg do case $ac_arg in -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) continue ;; *\'*) ac_arg=`printf "%s\n" "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac case $ac_pass in 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; 2) as_fn_append ac_configure_args1 " '$ac_arg'" if test $ac_must_keep_next = true; then ac_must_keep_next=false # Got value, back to normal. else case $ac_arg in *=* | --config-cache | -C | -disable-* | --disable-* \ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ | -with-* | --with-* | -without-* | --without-* | --x) case "$ac_configure_args0 " in "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; esac ;; -* ) ac_must_keep_next=true ;; esac fi as_fn_append ac_configure_args " '$ac_arg'" ;; esac done done { ac_configure_args0=; unset ac_configure_args0;} { ac_configure_args1=; unset ac_configure_args1;} # When interrupted or exit'd, cleanup temporary files, and complete # config.log. We remove comments because anyway the quotes in there # would cause problems or look ugly. # WARNING: Use '\'' to represent an apostrophe within the trap. # WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. trap 'exit_status=$? # Sanitize IFS. IFS=" "" $as_nl" # Save into config.log some information that might help in debugging. { echo printf "%s\n" "## ---------------- ## ## Cache variables. ## ## ---------------- ##" echo # The following way of writing the cache mishandles newlines in values, ( for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 printf "%s\n" "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( *${as_nl}ac_space=\ *) sed -n \ "s/'\''/'\''\\\\'\'''\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" ;; #( *) sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) echo printf "%s\n" "## ----------------- ## ## Output variables. ## ## ----------------- ##" echo for ac_var in $ac_subst_vars do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`printf "%s\n" "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac printf "%s\n" "$ac_var='\''$ac_val'\''" done | sort echo if test -n "$ac_subst_files"; then printf "%s\n" "## ------------------- ## ## File substitutions. ## ## ------------------- ##" echo for ac_var in $ac_subst_files do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`printf "%s\n" "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac printf "%s\n" "$ac_var='\''$ac_val'\''" done | sort echo fi if test -s confdefs.h; then printf "%s\n" "## ----------- ## ## confdefs.h. ## ## ----------- ##" echo cat confdefs.h echo fi test "$ac_signal" != 0 && printf "%s\n" "$as_me: caught signal $ac_signal" printf "%s\n" "$as_me: exit $exit_status" } >&5 rm -f core *.core core.conftest.* && rm -f -r conftest* confdefs* conf$$* $ac_clean_files && exit $exit_status ' 0 for ac_signal in 1 2 13 15; do trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal done ac_signal=0 # confdefs.h avoids OS command line length limits that DEFS can exceed. rm -f -r conftest* confdefs.h printf "%s\n" "/* confdefs.h */" > confdefs.h # Predefined preprocessor variables. printf "%s\n" "#define PACKAGE_NAME \"$PACKAGE_NAME\"" >>confdefs.h printf "%s\n" "#define PACKAGE_TARNAME \"$PACKAGE_TARNAME\"" >>confdefs.h printf "%s\n" "#define PACKAGE_VERSION \"$PACKAGE_VERSION\"" >>confdefs.h printf "%s\n" "#define PACKAGE_STRING \"$PACKAGE_STRING\"" >>confdefs.h printf "%s\n" "#define PACKAGE_BUGREPORT \"$PACKAGE_BUGREPORT\"" >>confdefs.h printf "%s\n" "#define PACKAGE_URL \"$PACKAGE_URL\"" >>confdefs.h # Let the site file select an alternate cache file if it wants to. # Prefer an explicitly selected file to automatically selected ones. if test -n "$CONFIG_SITE"; then ac_site_files="$CONFIG_SITE" elif test "x$prefix" != xNONE; then ac_site_files="$prefix/share/config.site $prefix/etc/config.site" else ac_site_files="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site" fi for ac_site_file in $ac_site_files do case $ac_site_file in #( */*) : ;; #( *) : ac_site_file=./$ac_site_file ;; esac if test -f "$ac_site_file" && test -r "$ac_site_file"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 printf "%s\n" "$as_me: loading site script $ac_site_file" >&6;} sed 's/^/| /' "$ac_site_file" >&5 . "$ac_site_file" \ || { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "failed to load site script $ac_site_file See \`config.log' for more details" "$LINENO" 5; } fi done if test -r "$cache_file"; then # Some versions of bash will fail to source /dev/null (special files # actually), so we avoid doing that. DJGPP emulates it as a regular file. if test /dev/null != "$cache_file" && test -f "$cache_file"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 printf "%s\n" "$as_me: loading cache $cache_file" >&6;} case $cache_file in [\\/]* | ?:[\\/]* ) . "$cache_file";; *) . "./$cache_file";; esac fi else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 printf "%s\n" "$as_me: creating cache $cache_file" >&6;} >$cache_file fi # Test code for whether the C++ compiler supports C++98 (global declarations) ac_cxx_conftest_cxx98_globals=' // Does the compiler advertise C++98 conformance? #if !defined __cplusplus || __cplusplus < 199711L # error "Compiler does not advertise C++98 conformance" #endif // These inclusions are to reject old compilers that // lack the unsuffixed header files. #include #include // and are *not* freestanding headers in C++98. extern void assert (int); namespace std { extern int strcmp (const char *, const char *); } // Namespaces, exceptions, and templates were all added after "C++ 2.0". using std::exception; using std::strcmp; namespace { void test_exception_syntax() { try { throw "test"; } catch (const char *s) { // Extra parentheses suppress a warning when building autoconf itself, // due to lint rules shared with more typical C programs. assert (!(strcmp) (s, "test")); } } template struct test_template { T const val; explicit test_template(T t) : val(t) {} template T add(U u) { return static_cast(u) + val; } }; } // anonymous namespace ' # Test code for whether the C++ compiler supports C++98 (body of main) ac_cxx_conftest_cxx98_main=' assert (argc); assert (! argv[0]); { test_exception_syntax (); test_template tt (2.0); assert (tt.add (4) == 6.0); assert (true && !false); } ' # Test code for whether the C++ compiler supports C++11 (global declarations) ac_cxx_conftest_cxx11_globals=' // Does the compiler advertise C++ 2011 conformance? #if !defined __cplusplus || __cplusplus < 201103L # error "Compiler does not advertise C++11 conformance" #endif namespace cxx11test { constexpr int get_val() { return 20; } struct testinit { int i; double d; }; class delegate { public: delegate(int n) : n(n) {} delegate(): delegate(2354) {} virtual int getval() { return this->n; }; protected: int n; }; class overridden : public delegate { public: overridden(int n): delegate(n) {} virtual int getval() override final { return this->n * 2; } }; class nocopy { public: nocopy(int i): i(i) {} nocopy() = default; nocopy(const nocopy&) = delete; nocopy & operator=(const nocopy&) = delete; private: int i; }; // for testing lambda expressions template Ret eval(Fn f, Ret v) { return f(v); } // for testing variadic templates and trailing return types template auto sum(V first) -> V { return first; } template auto sum(V first, Args... rest) -> V { return first + sum(rest...); } } ' # Test code for whether the C++ compiler supports C++11 (body of main) ac_cxx_conftest_cxx11_main=' { // Test auto and decltype auto a1 = 6538; auto a2 = 48573953.4; auto a3 = "String literal"; int total = 0; for (auto i = a3; *i; ++i) { total += *i; } decltype(a2) a4 = 34895.034; } { // Test constexpr short sa[cxx11test::get_val()] = { 0 }; } { // Test initializer lists cxx11test::testinit il = { 4323, 435234.23544 }; } { // Test range-based for int array[] = {9, 7, 13, 15, 4, 18, 12, 10, 5, 3, 14, 19, 17, 8, 6, 20, 16, 2, 11, 1}; for (auto &x : array) { x += 23; } } { // Test lambda expressions using cxx11test::eval; assert (eval ([](int x) { return x*2; }, 21) == 42); double d = 2.0; assert (eval ([&](double x) { return d += x; }, 3.0) == 5.0); assert (d == 5.0); assert (eval ([=](double x) mutable { return d += x; }, 4.0) == 9.0); assert (d == 5.0); } { // Test use of variadic templates using cxx11test::sum; auto a = sum(1); auto b = sum(1, 2); auto c = sum(1.0, 2.0, 3.0); } { // Test constructor delegation cxx11test::delegate d1; cxx11test::delegate d2(); cxx11test::delegate d3(45); } { // Test override and final cxx11test::overridden o1(55464); } { // Test nullptr char *c = nullptr; } { // Test template brackets test_template<::test_template> v(test_template(12)); } { // Unicode literals char const *utf8 = u8"UTF-8 string \u2500"; char16_t const *utf16 = u"UTF-8 string \u2500"; char32_t const *utf32 = U"UTF-32 string \u2500"; } ' # Test code for whether the C compiler supports C++11 (complete). ac_cxx_conftest_cxx11_program="${ac_cxx_conftest_cxx98_globals} ${ac_cxx_conftest_cxx11_globals} int main (int argc, char **argv) { int ok = 0; ${ac_cxx_conftest_cxx98_main} ${ac_cxx_conftest_cxx11_main} return ok; } " # Test code for whether the C compiler supports C++98 (complete). ac_cxx_conftest_cxx98_program="${ac_cxx_conftest_cxx98_globals} int main (int argc, char **argv) { int ok = 0; ${ac_cxx_conftest_cxx98_main} return ok; } " # Test code for whether the C compiler supports C89 (global declarations) ac_c_conftest_c89_globals=' /* Does the compiler advertise C89 conformance? Do not test the value of __STDC__, because some compilers set it to 0 while being otherwise adequately conformant. */ #if !defined __STDC__ # error "Compiler does not advertise C89 conformance" #endif #include #include struct stat; /* Most of the following tests are stolen from RCS 5.7 src/conf.sh. */ struct buf { int x; }; struct buf * (*rcsopen) (struct buf *, struct stat *, int); static char *e (char **p, int i) { return p[i]; } static char *f (char * (*g) (char **, int), char **p, ...) { char *s; va_list v; va_start (v,p); s = g (p, va_arg (v,int)); va_end (v); return s; } /* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has function prototypes and stuff, but not \xHH hex character constants. These do not provoke an error unfortunately, instead are silently treated as an "x". The following induces an error, until -std is added to get proper ANSI mode. Curiously \x00 != x always comes out true, for an array size at least. It is necessary to write \x00 == 0 to get something that is true only with -std. */ int osf4_cc_array ['\''\x00'\'' == 0 ? 1 : -1]; /* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters inside strings and character constants. */ #define FOO(x) '\''x'\'' int xlc6_cc_array[FOO(a) == '\''x'\'' ? 1 : -1]; int test (int i, double x); struct s1 {int (*f) (int a);}; struct s2 {int (*f) (double a);}; int pairnames (int, char **, int *(*)(struct buf *, struct stat *, int), int, int);' # Test code for whether the C compiler supports C89 (body of main). ac_c_conftest_c89_main=' ok |= (argc == 0 || f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]); ' # Test code for whether the C compiler supports C99 (global declarations) ac_c_conftest_c99_globals=' // Does the compiler advertise C99 conformance? #if !defined __STDC_VERSION__ || __STDC_VERSION__ < 199901L # error "Compiler does not advertise C99 conformance" #endif #include extern int puts (const char *); extern int printf (const char *, ...); extern int dprintf (int, const char *, ...); extern void *malloc (size_t); extern void free (void *); // Check varargs macros. These examples are taken from C99 6.10.3.5. // dprintf is used instead of fprintf to avoid needing to declare // FILE and stderr. #define debug(...) dprintf (2, __VA_ARGS__) #define showlist(...) puts (#__VA_ARGS__) #define report(test,...) ((test) ? puts (#test) : printf (__VA_ARGS__)) static void test_varargs_macros (void) { int x = 1234; int y = 5678; debug ("Flag"); debug ("X = %d\n", x); showlist (The first, second, and third items.); report (x>y, "x is %d but y is %d", x, y); } // Check long long types. #define BIG64 18446744073709551615ull #define BIG32 4294967295ul #define BIG_OK (BIG64 / BIG32 == 4294967297ull && BIG64 % BIG32 == 0) #if !BIG_OK #error "your preprocessor is broken" #endif #if BIG_OK #else #error "your preprocessor is broken" #endif static long long int bignum = -9223372036854775807LL; static unsigned long long int ubignum = BIG64; struct incomplete_array { int datasize; double data[]; }; struct named_init { int number; const wchar_t *name; double average; }; typedef const char *ccp; static inline int test_restrict (ccp restrict text) { // See if C++-style comments work. // Iterate through items via the restricted pointer. // Also check for declarations in for loops. for (unsigned int i = 0; *(text+i) != '\''\0'\''; ++i) continue; return 0; } // Check varargs and va_copy. static bool test_varargs (const char *format, ...) { va_list args; va_start (args, format); va_list args_copy; va_copy (args_copy, args); const char *str = ""; int number = 0; float fnumber = 0; while (*format) { switch (*format++) { case '\''s'\'': // string str = va_arg (args_copy, const char *); break; case '\''d'\'': // int number = va_arg (args_copy, int); break; case '\''f'\'': // float fnumber = va_arg (args_copy, double); break; default: break; } } va_end (args_copy); va_end (args); return *str && number && fnumber; } ' # Test code for whether the C compiler supports C99 (body of main). ac_c_conftest_c99_main=' // Check bool. _Bool success = false; success |= (argc != 0); // Check restrict. if (test_restrict ("String literal") == 0) success = true; char *restrict newvar = "Another string"; // Check varargs. success &= test_varargs ("s, d'\'' f .", "string", 65, 34.234); test_varargs_macros (); // Check flexible array members. struct incomplete_array *ia = malloc (sizeof (struct incomplete_array) + (sizeof (double) * 10)); ia->datasize = 10; for (int i = 0; i < ia->datasize; ++i) ia->data[i] = i * 1.234; // Check named initializers. struct named_init ni = { .number = 34, .name = L"Test wide string", .average = 543.34343, }; ni.number = 58; int dynamic_array[ni.number]; dynamic_array[0] = argv[0][0]; dynamic_array[ni.number - 1] = 543; // work around unused variable warnings ok |= (!success || bignum == 0LL || ubignum == 0uLL || newvar[0] == '\''x'\'' || dynamic_array[ni.number - 1] != 543); ' # Test code for whether the C compiler supports C11 (global declarations) ac_c_conftest_c11_globals=' // Does the compiler advertise C11 conformance? #if !defined __STDC_VERSION__ || __STDC_VERSION__ < 201112L # error "Compiler does not advertise C11 conformance" #endif // Check _Alignas. char _Alignas (double) aligned_as_double; char _Alignas (0) no_special_alignment; extern char aligned_as_int; char _Alignas (0) _Alignas (int) aligned_as_int; // Check _Alignof. enum { int_alignment = _Alignof (int), int_array_alignment = _Alignof (int[100]), char_alignment = _Alignof (char) }; _Static_assert (0 < -_Alignof (int), "_Alignof is signed"); // Check _Noreturn. int _Noreturn does_not_return (void) { for (;;) continue; } // Check _Static_assert. struct test_static_assert { int x; _Static_assert (sizeof (int) <= sizeof (long int), "_Static_assert does not work in struct"); long int y; }; // Check UTF-8 literals. #define u8 syntax error! char const utf8_literal[] = u8"happens to be ASCII" "another string"; // Check duplicate typedefs. typedef long *long_ptr; typedef long int *long_ptr; typedef long_ptr long_ptr; // Anonymous structures and unions -- taken from C11 6.7.2.1 Example 1. struct anonymous { union { struct { int i; int j; }; struct { int k; long int l; } w; }; int m; } v1; ' # Test code for whether the C compiler supports C11 (body of main). ac_c_conftest_c11_main=' _Static_assert ((offsetof (struct anonymous, i) == offsetof (struct anonymous, w.k)), "Anonymous union alignment botch"); v1.i = 2; v1.w.k = 5; ok |= v1.i != 5; ' # Test code for whether the C compiler supports C11 (complete). ac_c_conftest_c11_program="${ac_c_conftest_c89_globals} ${ac_c_conftest_c99_globals} ${ac_c_conftest_c11_globals} int main (int argc, char **argv) { int ok = 0; ${ac_c_conftest_c89_main} ${ac_c_conftest_c99_main} ${ac_c_conftest_c11_main} return ok; } " # Test code for whether the C compiler supports C99 (complete). ac_c_conftest_c99_program="${ac_c_conftest_c89_globals} ${ac_c_conftest_c99_globals} int main (int argc, char **argv) { int ok = 0; ${ac_c_conftest_c89_main} ${ac_c_conftest_c99_main} return ok; } " # Test code for whether the C compiler supports C89 (complete). ac_c_conftest_c89_program="${ac_c_conftest_c89_globals} int main (int argc, char **argv) { int ok = 0; ${ac_c_conftest_c89_main} return ok; } " as_fn_append ac_header_c_list " stdio.h stdio_h HAVE_STDIO_H" as_fn_append ac_header_c_list " stdlib.h stdlib_h HAVE_STDLIB_H" as_fn_append ac_header_c_list " string.h string_h HAVE_STRING_H" as_fn_append ac_header_c_list " inttypes.h inttypes_h HAVE_INTTYPES_H" as_fn_append ac_header_c_list " stdint.h stdint_h HAVE_STDINT_H" as_fn_append ac_header_c_list " strings.h strings_h HAVE_STRINGS_H" as_fn_append ac_header_c_list " sys/stat.h sys_stat_h HAVE_SYS_STAT_H" as_fn_append ac_header_c_list " sys/types.h sys_types_h HAVE_SYS_TYPES_H" as_fn_append ac_header_c_list " unistd.h unistd_h HAVE_UNISTD_H" # Auxiliary files required by this configure script. ac_aux_files="install-sh" # Locations in which to look for auxiliary files. ac_aux_dir_candidates="${srcdir}${PATH_SEPARATOR}${srcdir}/..${PATH_SEPARATOR}${srcdir}/../.." # Search for a directory containing all of the required auxiliary files, # $ac_aux_files, from the $PATH-style list $ac_aux_dir_candidates. # If we don't find one directory that contains all the files we need, # we report the set of missing files from the *first* directory in # $ac_aux_dir_candidates and give up. ac_missing_aux_files="" ac_first_candidate=: printf "%s\n" "$as_me:${as_lineno-$LINENO}: looking for aux files: $ac_aux_files" >&5 as_save_IFS=$IFS; IFS=$PATH_SEPARATOR as_found=false for as_dir in $ac_aux_dir_candidates do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac as_found=: printf "%s\n" "$as_me:${as_lineno-$LINENO}: trying $as_dir" >&5 ac_aux_dir_found=yes ac_install_sh= for ac_aux in $ac_aux_files do # As a special case, if "install-sh" is required, that requirement # can be satisfied by any of "install-sh", "install.sh", or "shtool", # and $ac_install_sh is set appropriately for whichever one is found. if test x"$ac_aux" = x"install-sh" then if test -f "${as_dir}install-sh"; then printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}install-sh found" >&5 ac_install_sh="${as_dir}install-sh -c" elif test -f "${as_dir}install.sh"; then printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}install.sh found" >&5 ac_install_sh="${as_dir}install.sh -c" elif test -f "${as_dir}shtool"; then printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}shtool found" >&5 ac_install_sh="${as_dir}shtool install -c" else ac_aux_dir_found=no if $ac_first_candidate; then ac_missing_aux_files="${ac_missing_aux_files} install-sh" else break fi fi else if test -f "${as_dir}${ac_aux}"; then printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}${ac_aux} found" >&5 else ac_aux_dir_found=no if $ac_first_candidate; then ac_missing_aux_files="${ac_missing_aux_files} ${ac_aux}" else break fi fi fi done if test "$ac_aux_dir_found" = yes; then ac_aux_dir="$as_dir" break fi ac_first_candidate=false as_found=false done IFS=$as_save_IFS if $as_found then : else $as_nop as_fn_error $? "cannot find required auxiliary files:$ac_missing_aux_files" "$LINENO" 5 fi # These three variables are undocumented and unsupported, # and are intended to be withdrawn in a future Autoconf release. # They can cause serious problems if a builder's source tree is in a directory # whose full name contains unusual characters. if test -f "${ac_aux_dir}config.guess"; then ac_config_guess="$SHELL ${ac_aux_dir}config.guess" fi if test -f "${ac_aux_dir}config.sub"; then ac_config_sub="$SHELL ${ac_aux_dir}config.sub" fi if test -f "$ac_aux_dir/configure"; then ac_configure="$SHELL ${ac_aux_dir}configure" fi # Check that the precious variables saved in the cache have kept the same # value. ac_cache_corrupted=false for ac_var in $ac_precious_vars; do eval ac_old_set=\$ac_cv_env_${ac_var}_set eval ac_new_set=\$ac_env_${ac_var}_set eval ac_old_val=\$ac_cv_env_${ac_var}_value eval ac_new_val=\$ac_env_${ac_var}_value case $ac_old_set,$ac_new_set in set,) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 printf "%s\n" "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} ac_cache_corrupted=: ;; ,set) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 printf "%s\n" "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} ac_cache_corrupted=: ;; ,);; *) if test "x$ac_old_val" != "x$ac_new_val"; then # differences in whitespace do not lead to failure. ac_old_val_w=`echo x $ac_old_val` ac_new_val_w=`echo x $ac_new_val` if test "$ac_old_val_w" != "$ac_new_val_w"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 printf "%s\n" "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} ac_cache_corrupted=: else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 printf "%s\n" "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} eval $ac_var=\$ac_old_val fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 printf "%s\n" "$as_me: former value: \`$ac_old_val'" >&2;} { printf "%s\n" "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 printf "%s\n" "$as_me: current value: \`$ac_new_val'" >&2;} fi;; esac # Pass precious variables to config.status. if test "$ac_new_set" = set; then case $ac_new_val in *\'*) ac_arg=$ac_var=`printf "%s\n" "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; *) ac_arg=$ac_var=$ac_new_val ;; esac case " $ac_configure_args " in *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. *) as_fn_append ac_configure_args " '$ac_arg'" ;; esac fi done if $ac_cache_corrupted; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 printf "%s\n" "$as_me: error: changes in the environment can compromise the build" >&2;} as_fn_error $? "run \`${MAKE-make} distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 fi ## -------------------- ## ## Main body of script. ## ## -------------------- ## ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu PACKAGE_ABIVERS=0.0 ac_config_headers="$ac_config_headers src/config.h" # Checks for programs. ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_cxx_compiler_gnu if test -z "$CXX"; then if test -n "$CCC"; then CXX=$CCC else if test -n "$ac_tool_prefix"; then for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC clang++ do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CXX+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$CXX"; then ac_cv_prog_CXX="$CXX" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CXX="$ac_tool_prefix$ac_prog" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CXX=$ac_cv_prog_CXX if test -n "$CXX"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CXX" >&5 printf "%s\n" "$CXX" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi test -n "$CXX" && break done fi if test -z "$CXX"; then ac_ct_CXX=$CXX for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC clang++ do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_CXX+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$ac_ct_CXX"; then ac_cv_prog_ac_ct_CXX="$ac_ct_CXX" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CXX="$ac_prog" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CXX=$ac_cv_prog_ac_ct_CXX if test -n "$ac_ct_CXX"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CXX" >&5 printf "%s\n" "$ac_ct_CXX" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi test -n "$ac_ct_CXX" && break done if test "x$ac_ct_CXX" = x; then CXX="g++" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CXX=$ac_ct_CXX fi fi fi fi # Provide some information about the compiler. printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for C++ compiler version" >&5 set X $ac_compile ac_compiler=$2 for ac_option in --version -v -V -qversion; do { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then sed '10a\ ... rest of stderr output deleted ... 10q' conftest.err >conftest.er1 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" # Try to create an executable without -o first, disregard a.out. # It will help us diagnose broken compilers, and finding out an intuition # of exeext. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the C++ compiler works" >&5 printf %s "checking whether the C++ compiler works... " >&6; } ac_link_default=`printf "%s\n" "$ac_link" | sed 's/ -o *conftest[^ ]*//'` # The possible output files: ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" ac_rmfiles= for ac_file in $ac_files do case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; * ) ac_rmfiles="$ac_rmfiles $ac_file";; esac done rm -f $ac_rmfiles if { { ac_try="$ac_link_default" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_link_default") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } then : # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. # So ignore a value of `no', otherwise this would lead to `EXEEXT = no' # in a Makefile. We should not override ac_cv_exeext if it was cached, # so that the user can short-circuit this test for compilers unknown to # Autoconf. for ac_file in $ac_files '' do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; [ab].out ) # We found the default executable, but exeext='' is most # certainly right. break;; *.* ) if test ${ac_cv_exeext+y} && test "$ac_cv_exeext" != no; then :; else ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` fi # We set ac_cv_exeext here because the later test for it is not # safe: cross compilers may not add the suffix if given an `-o' # argument, so we may need to know it at that point already. # Even if this section looks crufty: it has the advantage of # actually working. break;; * ) break;; esac done test "$ac_cv_exeext" = no && ac_cv_exeext= else $as_nop ac_file='' fi if test -z "$ac_file" then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "C++ compiler cannot create executables See \`config.log' for more details" "$LINENO" 5; } else $as_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for C++ compiler default output file name" >&5 printf %s "checking for C++ compiler default output file name... " >&6; } { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 printf "%s\n" "$ac_file" >&6; } ac_exeext=$ac_cv_exeext rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out ac_clean_files=$ac_clean_files_save { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 printf %s "checking for suffix of executables... " >&6; } if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } then : # If both `conftest.exe' and `conftest' are `present' (well, observable) # catch `conftest.exe'. For instance with Cygwin, `ls conftest' will # work properly (i.e., refer to `conftest.exe'), while it won't with # `rm'. for ac_file in conftest.exe conftest conftest.*; do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` break;; * ) break;; esac done else $as_nop { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of executables: cannot compile and link See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest conftest$ac_cv_exeext { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 printf "%s\n" "$ac_cv_exeext" >&6; } rm -f conftest.$ac_ext EXEEXT=$ac_cv_exeext ac_exeext=$EXEEXT cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main (void) { FILE *f = fopen ("conftest.out", "w"); return ferror (f) || fclose (f) != 0; ; return 0; } _ACEOF ac_clean_files="$ac_clean_files conftest.out" # Check that the compiler produces executables we can run. If not, either # the compiler is broken, or we cross compile. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 printf %s "checking whether we are cross compiling... " >&6; } if test "$cross_compiling" != yes; then { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if { ac_try='./conftest$ac_cv_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then cross_compiling=no else if test "$cross_compiling" = maybe; then cross_compiling=yes else { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot run C++ compiled programs. If you meant to cross compile, use \`--host'. See \`config.log' for more details" "$LINENO" 5; } fi fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 printf "%s\n" "$cross_compiling" >&6; } rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out ac_clean_files=$ac_clean_files_save { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 printf %s "checking for suffix of object files... " >&6; } if test ${ac_cv_objext+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF rm -f conftest.o conftest.obj if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } then : for ac_file in conftest.o conftest.obj conftest.*; do test -f "$ac_file" || continue; case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` break;; esac done else $as_nop printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of object files: cannot compile See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest.$ac_cv_objext conftest.$ac_ext fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 printf "%s\n" "$ac_cv_objext" >&6; } OBJEXT=$ac_cv_objext ac_objext=$OBJEXT { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports GNU C++" >&5 printf %s "checking whether the compiler supports GNU C++... " >&6; } if test ${ac_cv_cxx_compiler_gnu+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO" then : ac_compiler_gnu=yes else $as_nop ac_compiler_gnu=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ac_cv_cxx_compiler_gnu=$ac_compiler_gnu fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cxx_compiler_gnu" >&5 printf "%s\n" "$ac_cv_cxx_compiler_gnu" >&6; } ac_compiler_gnu=$ac_cv_cxx_compiler_gnu if test $ac_compiler_gnu = yes; then GXX=yes else GXX= fi ac_test_CXXFLAGS=${CXXFLAGS+y} ac_save_CXXFLAGS=$CXXFLAGS { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CXX accepts -g" >&5 printf %s "checking whether $CXX accepts -g... " >&6; } if test ${ac_cv_prog_cxx_g+y} then : printf %s "(cached) " >&6 else $as_nop ac_save_cxx_werror_flag=$ac_cxx_werror_flag ac_cxx_werror_flag=yes ac_cv_prog_cxx_g=no CXXFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO" then : ac_cv_prog_cxx_g=yes else $as_nop CXXFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO" then : else $as_nop ac_cxx_werror_flag=$ac_save_cxx_werror_flag CXXFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO" then : ac_cv_prog_cxx_g=yes fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ac_cxx_werror_flag=$ac_save_cxx_werror_flag fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_g" >&5 printf "%s\n" "$ac_cv_prog_cxx_g" >&6; } if test $ac_test_CXXFLAGS; then CXXFLAGS=$ac_save_CXXFLAGS elif test $ac_cv_prog_cxx_g = yes; then if test "$GXX" = yes; then CXXFLAGS="-g -O2" else CXXFLAGS="-g" fi else if test "$GXX" = yes; then CXXFLAGS="-O2" else CXXFLAGS= fi fi ac_prog_cxx_stdcxx=no if test x$ac_prog_cxx_stdcxx = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CXX option to enable C++11 features" >&5 printf %s "checking for $CXX option to enable C++11 features... " >&6; } if test ${ac_cv_prog_cxx_cxx11+y} then : printf %s "(cached) " >&6 else $as_nop ac_cv_prog_cxx_cxx11=no ac_save_CXX=$CXX cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_cxx_conftest_cxx11_program _ACEOF for ac_arg in '' -std=gnu++11 -std=gnu++0x -std=c++11 -std=c++0x -qlanglvl=extended0x -AA do CXX="$ac_save_CXX $ac_arg" if ac_fn_cxx_try_compile "$LINENO" then : ac_cv_prog_cxx_cxx11=$ac_arg fi rm -f core conftest.err conftest.$ac_objext conftest.beam test "x$ac_cv_prog_cxx_cxx11" != "xno" && break done rm -f conftest.$ac_ext CXX=$ac_save_CXX fi if test "x$ac_cv_prog_cxx_cxx11" = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 printf "%s\n" "unsupported" >&6; } else $as_nop if test "x$ac_cv_prog_cxx_cxx11" = x then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 printf "%s\n" "none needed" >&6; } else $as_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_cxx11" >&5 printf "%s\n" "$ac_cv_prog_cxx_cxx11" >&6; } CXX="$CXX $ac_cv_prog_cxx_cxx11" fi ac_cv_prog_cxx_stdcxx=$ac_cv_prog_cxx_cxx11 ac_prog_cxx_stdcxx=cxx11 fi fi if test x$ac_prog_cxx_stdcxx = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CXX option to enable C++98 features" >&5 printf %s "checking for $CXX option to enable C++98 features... " >&6; } if test ${ac_cv_prog_cxx_cxx98+y} then : printf %s "(cached) " >&6 else $as_nop ac_cv_prog_cxx_cxx98=no ac_save_CXX=$CXX cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_cxx_conftest_cxx98_program _ACEOF for ac_arg in '' -std=gnu++98 -std=c++98 -qlanglvl=extended -AA do CXX="$ac_save_CXX $ac_arg" if ac_fn_cxx_try_compile "$LINENO" then : ac_cv_prog_cxx_cxx98=$ac_arg fi rm -f core conftest.err conftest.$ac_objext conftest.beam test "x$ac_cv_prog_cxx_cxx98" != "xno" && break done rm -f conftest.$ac_ext CXX=$ac_save_CXX fi if test "x$ac_cv_prog_cxx_cxx98" = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 printf "%s\n" "unsupported" >&6; } else $as_nop if test "x$ac_cv_prog_cxx_cxx98" = x then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 printf "%s\n" "none needed" >&6; } else $as_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_cxx98" >&5 printf "%s\n" "$ac_cv_prog_cxx_cxx98" >&6; } CXX="$CXX $ac_cv_prog_cxx_cxx98" fi ac_cv_prog_cxx_stdcxx=$ac_cv_prog_cxx_cxx98 ac_prog_cxx_stdcxx=cxx98 fi fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. set dummy ${ac_tool_prefix}gcc; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}gcc" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="gcc" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 printf "%s\n" "$ac_ct_CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi else CC="$ac_cv_prog_CC" fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. set dummy ${ac_tool_prefix}cc; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}cc" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi fi if test -z "$CC"; then # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else ac_prog_rejected=no as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then if test "$as_dir$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then ac_prog_rejected=yes continue fi ac_cv_prog_CC="cc" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS if test $ac_prog_rejected = yes; then # We found a bogon in the path, so make sure we never use it. set dummy $ac_cv_prog_CC shift if test $# != 0; then # We chose a different compiler from the bogus one. # However, it has the same basename, so the bogon will be chosen # first if we set CC to just the basename; use the full file name. shift ac_cv_prog_CC="$as_dir$ac_word${1+' '}$@" fi fi fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then for ac_prog in cl.exe do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CC="$ac_tool_prefix$ac_prog" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi test -n "$CC" && break done fi if test -z "$CC"; then ac_ct_CC=$CC for ac_prog in cl.exe do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="$ac_prog" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 printf "%s\n" "$ac_ct_CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi test -n "$ac_ct_CC" && break done if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi fi fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}clang", so it can be a program name with args. set dummy ${ac_tool_prefix}clang; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}clang" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "clang", so it can be a program name with args. set dummy clang; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="clang" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 printf "%s\n" "$ac_ct_CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi else CC="$ac_cv_prog_CC" fi fi test -z "$CC" && { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "no acceptable C compiler found in \$PATH See \`config.log' for more details" "$LINENO" 5; } # Provide some information about the compiler. printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 set X $ac_compile ac_compiler=$2 for ac_option in --version -v -V -qversion -version; do { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then sed '10a\ ... rest of stderr output deleted ... 10q' conftest.err >conftest.er1 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports GNU C" >&5 printf %s "checking whether the compiler supports GNU C... " >&6; } if test ${ac_cv_c_compiler_gnu+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_compiler_gnu=yes else $as_nop ac_compiler_gnu=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ac_cv_c_compiler_gnu=$ac_compiler_gnu fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 printf "%s\n" "$ac_cv_c_compiler_gnu" >&6; } ac_compiler_gnu=$ac_cv_c_compiler_gnu if test $ac_compiler_gnu = yes; then GCC=yes else GCC= fi ac_test_CFLAGS=${CFLAGS+y} ac_save_CFLAGS=$CFLAGS { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 printf %s "checking whether $CC accepts -g... " >&6; } if test ${ac_cv_prog_cc_g+y} then : printf %s "(cached) " >&6 else $as_nop ac_save_c_werror_flag=$ac_c_werror_flag ac_c_werror_flag=yes ac_cv_prog_cc_g=no CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_g=yes else $as_nop CFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : else $as_nop ac_c_werror_flag=$ac_save_c_werror_flag CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_g=yes fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ac_c_werror_flag=$ac_save_c_werror_flag fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 printf "%s\n" "$ac_cv_prog_cc_g" >&6; } if test $ac_test_CFLAGS; then CFLAGS=$ac_save_CFLAGS elif test $ac_cv_prog_cc_g = yes; then if test "$GCC" = yes; then CFLAGS="-g -O2" else CFLAGS="-g" fi else if test "$GCC" = yes; then CFLAGS="-O2" else CFLAGS= fi fi ac_prog_cc_stdc=no if test x$ac_prog_cc_stdc = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C11 features" >&5 printf %s "checking for $CC option to enable C11 features... " >&6; } if test ${ac_cv_prog_cc_c11+y} then : printf %s "(cached) " >&6 else $as_nop ac_cv_prog_cc_c11=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_c_conftest_c11_program _ACEOF for ac_arg in '' -std=gnu11 do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_c11=$ac_arg fi rm -f core conftest.err conftest.$ac_objext conftest.beam test "x$ac_cv_prog_cc_c11" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi if test "x$ac_cv_prog_cc_c11" = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 printf "%s\n" "unsupported" >&6; } else $as_nop if test "x$ac_cv_prog_cc_c11" = x then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 printf "%s\n" "none needed" >&6; } else $as_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c11" >&5 printf "%s\n" "$ac_cv_prog_cc_c11" >&6; } CC="$CC $ac_cv_prog_cc_c11" fi ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c11 ac_prog_cc_stdc=c11 fi fi if test x$ac_prog_cc_stdc = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C99 features" >&5 printf %s "checking for $CC option to enable C99 features... " >&6; } if test ${ac_cv_prog_cc_c99+y} then : printf %s "(cached) " >&6 else $as_nop ac_cv_prog_cc_c99=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_c_conftest_c99_program _ACEOF for ac_arg in '' -std=gnu99 -std=c99 -c99 -qlanglvl=extc1x -qlanglvl=extc99 -AC99 -D_STDC_C99= do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_c99=$ac_arg fi rm -f core conftest.err conftest.$ac_objext conftest.beam test "x$ac_cv_prog_cc_c99" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi if test "x$ac_cv_prog_cc_c99" = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 printf "%s\n" "unsupported" >&6; } else $as_nop if test "x$ac_cv_prog_cc_c99" = x then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 printf "%s\n" "none needed" >&6; } else $as_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c99" >&5 printf "%s\n" "$ac_cv_prog_cc_c99" >&6; } CC="$CC $ac_cv_prog_cc_c99" fi ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c99 ac_prog_cc_stdc=c99 fi fi if test x$ac_prog_cc_stdc = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C89 features" >&5 printf %s "checking for $CC option to enable C89 features... " >&6; } if test ${ac_cv_prog_cc_c89+y} then : printf %s "(cached) " >&6 else $as_nop ac_cv_prog_cc_c89=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_c_conftest_c89_program _ACEOF for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_c89=$ac_arg fi rm -f core conftest.err conftest.$ac_objext conftest.beam test "x$ac_cv_prog_cc_c89" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi if test "x$ac_cv_prog_cc_c89" = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 printf "%s\n" "unsupported" >&6; } else $as_nop if test "x$ac_cv_prog_cc_c89" = x then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 printf "%s\n" "none needed" >&6; } else $as_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 printf "%s\n" "$ac_cv_prog_cc_c89" >&6; } CC="$CC $ac_cv_prog_cc_c89" fi ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c89 ac_prog_cc_stdc=c89 fi fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu # Find a good install program. We prefer a C program (faster), # so one script is as good as another. But avoid the broken or # incompatible versions: # SysV /etc/install, /usr/sbin/install # SunOS /usr/etc/install # IRIX /sbin/install # AIX /bin/install # AmigaOS /C/install, which installs bootblocks on floppy discs # AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag # AFS /usr/afsws/bin/install, which mishandles nonexistent args # SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" # OS/2's system install, which has a completely different semantic # ./install, which can be erroneously created by make from ./install.sh. # Reject install programs that cannot install multiple files. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 printf %s "checking for a BSD-compatible install... " >&6; } if test -z "$INSTALL"; then if test ${ac_cv_path_install+y} then : printf %s "(cached) " >&6 else $as_nop as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac # Account for fact that we put trailing slashes in our PATH walk. case $as_dir in #(( ./ | /[cC]/* | \ /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \ /usr/ucb/* ) ;; *) # OSF1 and SCO ODT 3.0 have their own names for install. # Don't use installbsd from OSF since it installs stuff as root # by default. for ac_prog in ginstall scoinst install; do for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_prog$ac_exec_ext"; then if test $ac_prog = install && grep dspmsg "$as_dir$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # AIX install. It has an incompatible calling convention. : elif test $ac_prog = install && grep pwplus "$as_dir$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # program-specific install script used by HP pwplus--don't use. : else rm -rf conftest.one conftest.two conftest.dir echo one > conftest.one echo two > conftest.two mkdir conftest.dir if "$as_dir$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir/" && test -s conftest.one && test -s conftest.two && test -s conftest.dir/conftest.one && test -s conftest.dir/conftest.two then ac_cv_path_install="$as_dir$ac_prog$ac_exec_ext -c" break 3 fi fi fi done done ;; esac done IFS=$as_save_IFS rm -rf conftest.one conftest.two conftest.dir fi if test ${ac_cv_path_install+y}; then INSTALL=$ac_cv_path_install else # As a last resort, use the slow shell script. Don't cache a # value for INSTALL within a source directory, because that will # break other packages using the cache if that directory is # removed, or if the value is a relative name. INSTALL=$ac_install_sh fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5 printf "%s\n" "$INSTALL" >&6; } # Use test -z because SunOS4 sh mishandles braces in ${var-val}. # It thinks the first close brace ends the variable substitution. test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether ln -s works" >&5 printf %s "checking whether ln -s works... " >&6; } LN_S=$as_ln_s if test "$LN_S" = "ln -s"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no, using $LN_S" >&5 printf "%s\n" "no, using $LN_S" >&6; } fi # Extract the first word of "lctest", so it can be a program name with args. set dummy lctest; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_testrunner+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$testrunner"; then ac_cv_prog_testrunner="$testrunner" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_testrunner="lctest" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_prog_testrunner" && ac_cv_prog_testrunner="maketest" fi fi testrunner=$ac_cv_prog_testrunner if test -n "$testrunner"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $testrunner" >&5 printf "%s\n" "$testrunner" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi TESTRUNNER=$testrunner for ac_prog in false do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_FALSE+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$FALSE"; then ac_cv_prog_FALSE="$FALSE" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_FALSE="$ac_prog" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi FALSE=$ac_cv_prog_FALSE if test -n "$FALSE"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $FALSE" >&5 printf "%s\n" "$FALSE" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi test -n "$FALSE" && break done test -n "$FALSE" || FALSE="/usr/bin/env false" # Check whether --enable-bloom-filters was given. if test ${enable_bloom_filters+y} then : enableval=$enable_bloom_filters; fi if test "x$enable_bloom_filters" = "xyes" then : printf "%s\n" "#define USE_BLOOM_FILTER 1" >>confdefs.h VEC_O="vec.o" MLD_BLOOM_FILTER="#define MLD_BLOOM_FILTER 1" fi if test -f "../../include/librecast.h"; then LIBRECAST_CFLAGS="-I\$(SOURCEDIR)/include" LIBMLD="-llibrecast" printf "%s\n" "#define HAVE_LIBLIBRECAST 1" >>confdefs.h else LIBMLD="-lmld" fi if test -f "../../src/librecast.c"; then LIBRECAST_LDFLAGS="-L\$(SOURCEDIR)/src -Wl,-rpath,\$(SOURCEDIR)/src" fi # Checks for libraries. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for dlsym in -ldl" >&5 printf %s "checking for dlsym in -ldl... " >&6; } if test ${ac_cv_lib_dl_dlsym+y} then : printf %s "(cached) " >&6 else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-ldl $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. The 'extern "C"' is for builds by C++ compilers; although this is not generally supported in C code supporting it here has little cost and some practical benefit (sr 110532). */ #ifdef __cplusplus extern "C" #endif char dlsym (void); int main (void) { return dlsym (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_dl_dlsym=yes else $as_nop ac_cv_lib_dl_dlsym=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlsym" >&5 printf "%s\n" "$ac_cv_lib_dl_dlsym" >&6; } if test "x$ac_cv_lib_dl_dlsym" = xyes then : printf "%s\n" "#define HAVE_LIBDL 1" >>confdefs.h LIBS="-ldl $LIBS" fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for lc_ctx_new in -llibrecast" >&5 printf %s "checking for lc_ctx_new in -llibrecast... " >&6; } if test ${ac_cv_lib_librecast_lc_ctx_new+y} then : printf %s "(cached) " >&6 else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-llibrecast $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. The 'extern "C"' is for builds by C++ compilers; although this is not generally supported in C code supporting it here has little cost and some practical benefit (sr 110532). */ #ifdef __cplusplus extern "C" #endif char lc_ctx_new (void); int main (void) { return lc_ctx_new (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_librecast_lc_ctx_new=yes else $as_nop ac_cv_lib_librecast_lc_ctx_new=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_librecast_lc_ctx_new" >&5 printf "%s\n" "$ac_cv_lib_librecast_lc_ctx_new" >&6; } if test "x$ac_cv_lib_librecast_lc_ctx_new" = xyes then : printf "%s\n" "#define HAVE_LIBLIBRECAST 1" >>confdefs.h LIBS="-llibrecast $LIBS" fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for log2 in -lm" >&5 printf %s "checking for log2 in -lm... " >&6; } if test ${ac_cv_lib_m_log2+y} then : printf %s "(cached) " >&6 else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lm $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. The 'extern "C"' is for builds by C++ compilers; although this is not generally supported in C code supporting it here has little cost and some practical benefit (sr 110532). */ #ifdef __cplusplus extern "C" #endif char log2 (void); int main (void) { return log2 (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_m_log2=yes else $as_nop ac_cv_lib_m_log2=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_m_log2" >&5 printf "%s\n" "$ac_cv_lib_m_log2" >&6; } if test "x$ac_cv_lib_m_log2" = xyes then : printf "%s\n" "#define HAVE_LIBM 1" >>confdefs.h LIBS="-lm $LIBS" fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for pthread_create in -lpthread" >&5 printf %s "checking for pthread_create in -lpthread... " >&6; } if test ${ac_cv_lib_pthread_pthread_create+y} then : printf %s "(cached) " >&6 else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lpthread $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. The 'extern "C"' is for builds by C++ compilers; although this is not generally supported in C code supporting it here has little cost and some practical benefit (sr 110532). */ #ifdef __cplusplus extern "C" #endif char pthread_create (void); int main (void) { return pthread_create (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_pthread_pthread_create=yes else $as_nop ac_cv_lib_pthread_pthread_create=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthread_pthread_create" >&5 printf "%s\n" "$ac_cv_lib_pthread_pthread_create" >&6; } if test "x$ac_cv_lib_pthread_pthread_create" = xyes then : printf "%s\n" "#define HAVE_LIBPTHREAD 1" >>confdefs.h LIBS="-lpthread $LIBS" fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing clock_gettime" >&5 printf %s "checking for library containing clock_gettime... " >&6; } if test ${ac_cv_search_clock_gettime+y} then : printf %s "(cached) " >&6 else $as_nop ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. The 'extern "C"' is for builds by C++ compilers; although this is not generally supported in C code supporting it here has little cost and some practical benefit (sr 110532). */ #ifdef __cplusplus extern "C" #endif char clock_gettime (void); int main (void) { return clock_gettime (); ; return 0; } _ACEOF for ac_lib in '' rt do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO" then : ac_cv_search_clock_gettime=$ac_res fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext if test ${ac_cv_search_clock_gettime+y} then : break fi done if test ${ac_cv_search_clock_gettime+y} then : else $as_nop ac_cv_search_clock_gettime=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_clock_gettime" >&5 printf "%s\n" "$ac_cv_search_clock_gettime" >&6; } ac_res=$ac_cv_search_clock_gettime if test "$ac_res" != no then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" fi # Checks for functions. for ac_func in clock_gettime getpagesize memset socket strerror do : as_ac_var=`printf "%s\n" "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" if eval test \"x\$"$as_ac_var"\" = x"yes" then : cat >>confdefs.h <<_ACEOF #define `printf "%s\n" "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF else $as_nop as_fn_error $? "required function missing" "$LINENO" 5 fi done # Checks for header files. ac_header= ac_cache= for ac_item in $ac_header_c_list do if test $ac_cache; then ac_fn_c_check_header_compile "$LINENO" $ac_header ac_cv_header_$ac_cache "$ac_includes_default" if eval test \"x\$ac_cv_header_$ac_cache\" = xyes; then printf "%s\n" "#define $ac_item 1" >> confdefs.h fi ac_header= ac_cache= elif test $ac_header; then ac_cache=$ac_item else ac_header=$ac_item fi done if test $ac_cv_header_stdlib_h = yes && test $ac_cv_header_string_h = yes then : printf "%s\n" "#define STDC_HEADERS 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "asm/types.h" "ac_cv_header_asm_types_h" "$ac_includes_default" if test "x$ac_cv_header_asm_types_h" = xyes then : printf "%s\n" "#define HAVE_ASM_TYPES_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "fcntl.h" "ac_cv_header_fcntl_h" "$ac_includes_default" if test "x$ac_cv_header_fcntl_h" = xyes then : printf "%s\n" "#define HAVE_FCNTL_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "net/bpf.h" "ac_cv_header_net_bpf_h" "$ac_includes_default" if test "x$ac_cv_header_net_bpf_h" = xyes then : printf "%s\n" "#define HAVE_NET_BPF_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "netdb.h" "ac_cv_header_netdb_h" "$ac_includes_default" if test "x$ac_cv_header_netdb_h" = xyes then : printf "%s\n" "#define HAVE_NETDB_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "netinet/icmp6.h" "ac_cv_header_netinet_icmp6_h" "$ac_includes_default" if test "x$ac_cv_header_netinet_icmp6_h" = xyes then : printf "%s\n" "#define HAVE_NETINET_ICMP6_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "netinet/in.h" "ac_cv_header_netinet_in_h" "$ac_includes_default" if test "x$ac_cv_header_netinet_in_h" = xyes then : printf "%s\n" "#define HAVE_NETINET_IN_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "netinet6/ip6_mroute.h" "ac_cv_header_netinet6_ip6_mroute_h" " # include # include # include # include " if test "x$ac_cv_header_netinet6_ip6_mroute_h" = xyes then : printf "%s\n" "#define HAVE_NETINET6_IP6_MROUTE_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "stdint.h" "ac_cv_header_stdint_h" "$ac_includes_default" if test "x$ac_cv_header_stdint_h" = xyes then : printf "%s\n" "#define HAVE_STDINT_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "sys/socket.h" "ac_cv_header_sys_socket_h" "$ac_includes_default" if test "x$ac_cv_header_sys_socket_h" = xyes then : printf "%s\n" "#define HAVE_SYS_SOCKET_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "sys/time.h" "ac_cv_header_sys_time_h" "$ac_includes_default" if test "x$ac_cv_header_sys_time_h" = xyes then : printf "%s\n" "#define HAVE_SYS_TIME_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "endian.h" "ac_cv_header_endian_h" "$ac_includes_default" if test "x$ac_cv_header_endian_h" = xyes then : printf "%s\n" "#define HAVE_ENDIAN_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "sys/endian.h" "ac_cv_header_sys_endian_h" "$ac_includes_default" if test "x$ac_cv_header_sys_endian_h" = xyes then : printf "%s\n" "#define HAVE_SYS_ENDIAN_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "libkern/OSByteOrder.h" "ac_cv_header_libkern_OSByteOrder_h" "$ac_includes_default" if test "x$ac_cv_header_libkern_OSByteOrder_h" = xyes then : printf "%s\n" "#define HAVE_LIBKERN_OSBYTEORDER_H 1" >>confdefs.h fi # wanted by bloom filter code ac_fn_c_check_header_compile "$LINENO" "arpa/inet.h" "ac_cv_header_arpa_inet_h" "$ac_includes_default" if test "x$ac_cv_header_arpa_inet_h" = xyes then : printf "%s\n" "#define HAVE_ARPA_INET_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "sys/ioctl.h" "ac_cv_header_sys_ioctl_h" "$ac_includes_default" if test "x$ac_cv_header_sys_ioctl_h" = xyes then : printf "%s\n" "#define HAVE_SYS_IOCTL_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "sys/param.h" "ac_cv_header_sys_param_h" "$ac_includes_default" if test "x$ac_cv_header_sys_param_h" = xyes then : printf "%s\n" "#define HAVE_SYS_PARAM_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "unistd.h" "ac_cv_header_unistd_h" "$ac_includes_default" if test "x$ac_cv_header_unistd_h" = xyes then : printf "%s\n" "#define HAVE_UNISTD_H 1" >>confdefs.h fi # Checks for typedefs, structures, and compiler characteristics. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for inline" >&5 printf %s "checking for inline... " >&6; } if test ${ac_cv_c_inline+y} then : printf %s "(cached) " >&6 else $as_nop ac_cv_c_inline=no for ac_kw in inline __inline__ __inline; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifndef __cplusplus typedef int foo_t; static $ac_kw foo_t static_foo (void) {return 0; } $ac_kw foo_t foo (void) {return 0; } #endif _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_c_inline=$ac_kw fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext test "$ac_cv_c_inline" != no && break done fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_inline" >&5 printf "%s\n" "$ac_cv_c_inline" >&6; } case $ac_cv_c_inline in inline | yes) ;; *) case $ac_cv_c_inline in no) ac_val=;; *) ac_val=$ac_cv_c_inline;; esac cat >>confdefs.h <<_ACEOF #ifndef __cplusplus #define inline $ac_val #endif _ACEOF ;; esac ac_fn_c_check_type "$LINENO" "size_t" "ac_cv_type_size_t" "$ac_includes_default" if test "x$ac_cv_type_size_t" = xyes then : else $as_nop printf "%s\n" "#define size_t unsigned int" >>confdefs.h fi ac_fn_c_check_type "$LINENO" "ssize_t" "ac_cv_type_ssize_t" "$ac_includes_default" if test "x$ac_cv_type_ssize_t" = xyes then : else $as_nop printf "%s\n" "#define ssize_t int" >>confdefs.h fi ac_fn_c_find_uintX_t "$LINENO" "64" "ac_cv_c_uint64_t" case $ac_cv_c_uint64_t in #( no|yes) ;; #( *) printf "%s\n" "#define _UINT64_T 1" >>confdefs.h printf "%s\n" "#define uint64_t $ac_cv_c_uint64_t" >>confdefs.h ;; esac ac_fn_c_find_uintX_t "$LINENO" "32" "ac_cv_c_uint32_t" case $ac_cv_c_uint32_t in #( no|yes) ;; #( *) printf "%s\n" "#define _UINT32_T 1" >>confdefs.h printf "%s\n" "#define uint32_t $ac_cv_c_uint32_t" >>confdefs.h ;; esac ac_fn_c_find_uintX_t "$LINENO" "16" "ac_cv_c_uint16_t" case $ac_cv_c_uint16_t in #( no|yes) ;; #( *) printf "%s\n" "#define uint16_t $ac_cv_c_uint16_t" >>confdefs.h ;; esac ac_fn_c_find_uintX_t "$LINENO" "8" "ac_cv_c_uint8_t" case $ac_cv_c_uint8_t in #( no|yes) ;; #( *) printf "%s\n" "#define _UINT8_T 1" >>confdefs.h printf "%s\n" "#define uint8_t $ac_cv_c_uint8_t" >>confdefs.h ;; esac # Checks for library functions. ac_config_files="$ac_config_files Makefile src/Makefile test/Makefile include/mld.h" cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure # tests run on this system so they can be shared between configure # scripts and configure runs, see configure's option --config-cache. # It is not useful on other systems. If it contains results you don't # want to keep, you may remove or edit it. # # config.status only pays attention to the cache file if you give it # the --recheck option to rerun configure. # # `ac_cv_env_foo' variables (set or unset) will be overridden when # loading this file, other *unset* `ac_cv_foo' will be assigned the # following values. _ACEOF # The following way of writing the cache mishandles newlines in values, # but we know of no workaround that is simple, portable, and efficient. # So, we kill variables containing newlines. # Ultrix sh set writes to stderr and can't be redirected directly, # and sets the high bit in the cache file unless we assign to the vars. ( for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 printf "%s\n" "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space=' '; set) 2>&1` in #( *${as_nl}ac_space=\ *) # `set' does not quote correctly, so add quotes: double-quote # substitution turns \\\\ into \\, and sed turns \\ into \. sed -n \ "s/'/'\\\\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" ;; #( *) # `set' quotes correctly as required by POSIX, so do not add quotes. sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) | sed ' /^ac_cv_env_/b end t clear :clear s/^\([^=]*\)=\(.*[{}].*\)$/test ${\1+y} || &/ t end s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ :end' >>confcache if diff "$cache_file" confcache >/dev/null 2>&1; then :; else if test -w "$cache_file"; then if test "x$cache_file" != "x/dev/null"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 printf "%s\n" "$as_me: updating cache $cache_file" >&6;} if test ! -f "$cache_file" || test -h "$cache_file"; then cat confcache >"$cache_file" else case $cache_file in #( */* | ?:*) mv -f confcache "$cache_file"$$ && mv -f "$cache_file"$$ "$cache_file" ;; #( *) mv -f confcache "$cache_file" ;; esac fi fi else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 printf "%s\n" "$as_me: not updating unwritable cache $cache_file" >&6;} fi fi rm -f confcache test "x$prefix" = xNONE && prefix=$ac_default_prefix # Let make expand exec_prefix. test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' DEFS=-DHAVE_CONFIG_H ac_libobjs= ac_ltlibobjs= U= for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue # 1. Remove the extension, and $U if already installed. ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' ac_i=`printf "%s\n" "$ac_i" | sed "$ac_script"` # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR # will be set to the directory where LIBOBJS objects are built. as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' done LIBOBJS=$ac_libobjs LTLIBOBJS=$ac_ltlibobjs : "${CONFIG_STATUS=./config.status}" ac_write_fail=0 ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files $CONFIG_STATUS" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 printf "%s\n" "$as_me: creating $CONFIG_STATUS" >&6;} as_write_fail=0 cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 #! $SHELL # Generated by $as_me. # Run this file to recreate the current configuration. # Compiler output produced by configure, useful for debugging # configure, is in config.log if it exists. debug=false ac_cs_recheck=false ac_cs_silent=false SHELL=\${CONFIG_SHELL-$SHELL} export SHELL _ASEOF cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh as_nop=: if test ${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else $as_nop case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi # Reset variables that may have inherited troublesome values from # the environment. # IFS needs to be set, to space, tab, and newline, in precisely that order. # (If _AS_PATH_WALK were called with IFS unset, it would have the # side effect of setting IFS to empty, thus disabling word splitting.) # Quoting is to prevent editors from complaining about space-tab. as_nl=' ' export as_nl IFS=" "" $as_nl" PS1='$ ' PS2='> ' PS4='+ ' # Ensure predictable behavior from utilities with locale-dependent output. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # We cannot yet rely on "unset" to work, but we need these variables # to be unset--not just set to an empty or harmless value--now, to # avoid bugs in old shells (e.g. pre-3.0 UWIN ksh). This construct # also avoids known problems related to "unset" and subshell syntax # in other old shells (e.g. bash 2.01 and pdksh 5.2.14). for as_var in BASH_ENV ENV MAIL MAILPATH CDPATH do eval test \${$as_var+y} \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done # Ensure that fds 0, 1, and 2 are open. if (exec 3>&0) 2>/dev/null; then :; else exec 0&1) 2>/dev/null; then :; else exec 1>/dev/null; fi if (exec 3>&2) ; then :; else exec 2>/dev/null; fi # The user is always right. if ${PATH_SEPARATOR+false} :; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac test -r "$as_dir$0" && as_myself=$as_dir$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then printf "%s\n" "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi printf "%s\n" "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null then : eval 'as_fn_append () { eval $1+=\$2 }' else $as_nop as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null then : eval 'as_fn_arith () { as_val=$(( $* )) }' else $as_nop as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || printf "%s\n" X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits # Determine whether it's possible to make 'echo' print without a newline. # These variables are no longer used directly by Autoconf, but are AC_SUBSTed # for compatibility with existing Makefiles. ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac # For backward compatibility with old third-party macros, we provide # the shell variables $as_echo and $as_echo_n. New code should use # AS_ECHO(["message"]) and AS_ECHO_N(["message"]), respectively. as_echo='printf %s\n' as_echo_n='printf %s' rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -pR' fi else as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`printf "%s\n" "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || printf "%s\n" X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi # as_fn_executable_p FILE # ----------------------- # Test if FILE is an executable regular file. as_fn_executable_p () { test -f "$1" && test -x "$1" } # as_fn_executable_p as_test_x='test -x' as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" exec 6>&1 ## ----------------------------------- ## ## Main body of $CONFIG_STATUS script. ## ## ----------------------------------- ## _ASEOF test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Save the log message, to keep $0 and so on meaningful, and to # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" This file was extended by mld $as_me 0.0.0, which was generated by GNU Autoconf 2.71. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS CONFIG_LINKS = $CONFIG_LINKS CONFIG_COMMANDS = $CONFIG_COMMANDS $ $0 $@ on `(hostname || uname -n) 2>/dev/null | sed 1q` " _ACEOF case $ac_config_files in *" "*) set x $ac_config_files; shift; ac_config_files=$*;; esac case $ac_config_headers in *" "*) set x $ac_config_headers; shift; ac_config_headers=$*;; esac cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # Files that config.status was made for. config_files="$ac_config_files" config_headers="$ac_config_headers" _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 ac_cs_usage="\ \`$as_me' instantiates files and other configuration actions from templates according to the current configuration. Unless the files and actions are specified as TAGs, all are instantiated by default. Usage: $0 [OPTION]... [TAG]... -h, --help print this help, then exit -V, --version print version number and configuration settings, then exit --config print configuration, then exit -q, --quiet, --silent do not print progress messages -d, --debug don't remove temporary files --recheck update $as_me by reconfiguring in the same conditions --file=FILE[:TEMPLATE] instantiate the configuration file FILE --header=FILE[:TEMPLATE] instantiate the configuration header FILE Configuration files: $config_files Configuration headers: $config_headers Report bugs to ." _ACEOF ac_cs_config=`printf "%s\n" "$ac_configure_args" | sed "$ac_safe_unquote"` ac_cs_config_escaped=`printf "%s\n" "$ac_cs_config" | sed "s/^ //; s/'/'\\\\\\\\''/g"` cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config='$ac_cs_config_escaped' ac_cs_version="\\ mld config.status 0.0.0 configured by $0, generated by GNU Autoconf 2.71, with options \\"\$ac_cs_config\\" Copyright (C) 2021 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." ac_pwd='$ac_pwd' srcdir='$srcdir' INSTALL='$INSTALL' test -n "\$AWK" || AWK=awk _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # The default lists apply if the user does not specify any file. ac_need_defaults=: while test $# != 0 do case $1 in --*=?*) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` ac_shift=: ;; --*=) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg= ac_shift=: ;; *) ac_option=$1 ac_optarg=$2 ac_shift=shift ;; esac case $ac_option in # Handling of the options. -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) ac_cs_recheck=: ;; --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) printf "%s\n" "$ac_cs_version"; exit ;; --config | --confi | --conf | --con | --co | --c ) printf "%s\n" "$ac_cs_config"; exit ;; --debug | --debu | --deb | --de | --d | -d ) debug=: ;; --file | --fil | --fi | --f ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`printf "%s\n" "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; '') as_fn_error $? "missing file argument" ;; esac as_fn_append CONFIG_FILES " '$ac_optarg'" ac_need_defaults=false;; --header | --heade | --head | --hea ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`printf "%s\n" "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; esac as_fn_append CONFIG_HEADERS " '$ac_optarg'" ac_need_defaults=false;; --he | --h) # Conflict between --help and --header as_fn_error $? "ambiguous option: \`$1' Try \`$0 --help' for more information.";; --help | --hel | -h ) printf "%s\n" "$ac_cs_usage"; exit ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil | --si | --s) ac_cs_silent=: ;; # This is an error. -*) as_fn_error $? "unrecognized option: \`$1' Try \`$0 --help' for more information." ;; *) as_fn_append ac_config_targets " $1" ac_need_defaults=false ;; esac shift done ac_configure_extra_args= if $ac_cs_silent; then exec 6>/dev/null ac_configure_extra_args="$ac_configure_extra_args --silent" fi _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 if \$ac_cs_recheck; then set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion shift \printf "%s\n" "running CONFIG_SHELL=$SHELL \$*" >&6 CONFIG_SHELL='$SHELL' export CONFIG_SHELL exec "\$@" fi _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 exec 5>>config.log { echo sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX ## Running $as_me. ## _ASBOX printf "%s\n" "$ac_log" } >&5 _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Handling of arguments. for ac_config_target in $ac_config_targets do case $ac_config_target in "src/config.h") CONFIG_HEADERS="$CONFIG_HEADERS src/config.h" ;; "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; "src/Makefile") CONFIG_FILES="$CONFIG_FILES src/Makefile" ;; "test/Makefile") CONFIG_FILES="$CONFIG_FILES test/Makefile" ;; "include/mld.h") CONFIG_FILES="$CONFIG_FILES include/mld.h" ;; *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; esac done # If the user did not use the arguments to specify the items to instantiate, # then the envvar interface is used. Set only those that are not. # We use the long form for the default assignment because of an extremely # bizarre bug on SunOS 4.1.3. if $ac_need_defaults; then test ${CONFIG_FILES+y} || CONFIG_FILES=$config_files test ${CONFIG_HEADERS+y} || CONFIG_HEADERS=$config_headers fi # Have a temporary directory for convenience. Make it in the build tree # simply because there is no reason against having it here, and in addition, # creating and moving files from /tmp can sometimes cause problems. # Hook for its removal unless debugging. # Note that there is a small window in which the directory will not be cleaned: # after its creation but before its name has been assigned to `$tmp'. $debug || { tmp= ac_tmp= trap 'exit_status=$? : "${ac_tmp:=$tmp}" { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status ' 0 trap 'as_fn_exit 1' 1 2 13 15 } # Create a (secure) tmp directory for tmp files. { tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && test -d "$tmp" } || { tmp=./conf$$-$RANDOM (umask 077 && mkdir "$tmp") } || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 ac_tmp=$tmp # Set up the scripts for CONFIG_FILES section. # No need to generate them if there are no CONFIG_FILES. # This happens for instance with `./config.status config.h'. if test -n "$CONFIG_FILES"; then ac_cr=`echo X | tr X '\015'` # On cygwin, bash can eat \r inside `` if the user requested igncr. # But we know of no other shell where ac_cr would be empty at this # point, so we can use a bashism as a fallback. if test "x$ac_cr" = x; then eval ac_cr=\$\'\\r\' fi ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then ac_cs_awk_cr='\\r' else ac_cs_awk_cr=$ac_cr fi echo 'BEGIN {' >"$ac_tmp/subs1.awk" && _ACEOF { echo "cat >conf$$subs.awk <<_ACEOF" && echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && echo "_ACEOF" } >conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` ac_delim='%!_!# ' for ac_last_try in false false false false false :; do . ./conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` if test $ac_delim_n = $ac_delim_num; then break elif $ac_last_try; then as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done rm -f conf$$subs.sh cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK && _ACEOF sed -n ' h s/^/S["/; s/!.*/"]=/ p g s/^[^!]*!// :repl t repl s/'"$ac_delim"'$// t delim :nl h s/\(.\{148\}\)..*/\1/ t more1 s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ p n b repl :more1 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t nl :delim h s/\(.\{148\}\)..*/\1/ t more2 s/["\\]/\\&/g; s/^/"/; s/$/"/ p b :more2 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t delim ' >$CONFIG_STATUS || ac_write_fail=1 rm -f conf$$subs.awk cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACAWK cat >>"\$ac_tmp/subs1.awk" <<_ACAWK && for (key in S) S_is_set[key] = 1 FS = "" } { line = $ 0 nfields = split(line, field, "@") substed = 0 len = length(field[1]) for (i = 2; i < nfields; i++) { key = field[i] keylen = length(key) if (S_is_set[key]) { value = S[key] line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) len += length(value) + length(field[++i]) substed = 1 } else len += 1 + keylen } print line } _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" else cat fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 _ACEOF # VPATH may cause trouble with some makes, so we remove sole $(srcdir), # ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and # trailing colons and then remove the whole line if VPATH becomes empty # (actually we leave an empty line to preserve line numbers). if test "x$srcdir" = x.; then ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ h s/// s/^/:/ s/[ ]*$/:/ s/:\$(srcdir):/:/g s/:\${srcdir}:/:/g s/:@srcdir@:/:/g s/^:*// s/:*$// x s/\(=[ ]*\).*/\1/ G s/\n// s/^[^=]*=[ ]*$// }' fi cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 fi # test -n "$CONFIG_FILES" # Set up the scripts for CONFIG_HEADERS section. # No need to generate them if there are no CONFIG_HEADERS. # This happens for instance with `./config.status Makefile'. if test -n "$CONFIG_HEADERS"; then cat >"$ac_tmp/defines.awk" <<\_ACAWK || BEGIN { _ACEOF # Transform confdefs.h into an awk script `defines.awk', embedded as # here-document in config.status, that substitutes the proper values into # config.h.in to produce config.h. # Create a delimiter string that does not exist in confdefs.h, to ease # handling of long lines. ac_delim='%!_!# ' for ac_last_try in false false :; do ac_tt=`sed -n "/$ac_delim/p" confdefs.h` if test -z "$ac_tt"; then break elif $ac_last_try; then as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done # For the awk script, D is an array of macro values keyed by name, # likewise P contains macro parameters if any. Preserve backslash # newline sequences. ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]* sed -n ' s/.\{148\}/&'"$ac_delim"'/g t rset :rset s/^[ ]*#[ ]*define[ ][ ]*/ / t def d :def s/\\$// t bsnl s/["\\]/\\&/g s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ D["\1"]=" \3"/p s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2"/p d :bsnl s/["\\]/\\&/g s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ D["\1"]=" \3\\\\\\n"\\/p t cont s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p t cont d :cont n s/.\{148\}/&'"$ac_delim"'/g t clear :clear s/\\$// t bsnlc s/["\\]/\\&/g; s/^/"/; s/$/"/p d :bsnlc s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p b cont ' >$CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 for (key in D) D_is_set[key] = 1 FS = "" } /^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ { line = \$ 0 split(line, arg, " ") if (arg[1] == "#") { defundef = arg[2] mac1 = arg[3] } else { defundef = substr(arg[1], 2) mac1 = arg[2] } split(mac1, mac2, "(") #) macro = mac2[1] prefix = substr(line, 1, index(line, defundef) - 1) if (D_is_set[macro]) { # Preserve the white space surrounding the "#". print prefix "define", macro P[macro] D[macro] next } else { # Replace #undef with comments. This is necessary, for example, # in the case of _POSIX_SOURCE, which is predefined and required # on some systems where configure will not decide to define it. if (defundef == "undef") { print "/*", prefix defundef, macro, "*/" next } } } { print } _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 as_fn_error $? "could not setup config headers machinery" "$LINENO" 5 fi # test -n "$CONFIG_HEADERS" eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS " shift for ac_tag do case $ac_tag in :[FHLC]) ac_mode=$ac_tag; continue;; esac case $ac_mode$ac_tag in :[FHL]*:*);; :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; :[FH]-) ac_tag=-:-;; :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; esac ac_save_IFS=$IFS IFS=: set x $ac_tag IFS=$ac_save_IFS shift ac_file=$1 shift case $ac_mode in :L) ac_source=$1;; :[FH]) ac_file_inputs= for ac_f do case $ac_f in -) ac_f="$ac_tmp/stdin";; *) # Look for the file first in the build tree, then in the source tree # (if the path is not absolute). The absolute path cannot be DOS-style, # because $ac_f cannot contain `:'. test -f "$ac_f" || case $ac_f in [\\/$]*) false;; *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; esac || as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; esac case $ac_f in *\'*) ac_f=`printf "%s\n" "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac as_fn_append ac_file_inputs " '$ac_f'" done # Let's still pretend it is `configure' which instantiates (i.e., don't # use $as_me), people would be surprised to read: # /* config.h. Generated by config.status. */ configure_input='Generated from '` printf "%s\n" "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' `' by configure.' if test x"$ac_file" != x-; then configure_input="$ac_file. $configure_input" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 printf "%s\n" "$as_me: creating $ac_file" >&6;} fi # Neutralize special characters interpreted by sed in replacement strings. case $configure_input in #( *\&* | *\|* | *\\* ) ac_sed_conf_input=`printf "%s\n" "$configure_input" | sed 's/[\\\\&|]/\\\\&/g'`;; #( *) ac_sed_conf_input=$configure_input;; esac case $ac_tag in *:-:* | *:-) cat >"$ac_tmp/stdin" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; esac ;; esac ac_dir=`$as_dirname -- "$ac_file" || $as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$ac_file" : 'X\(//\)[^/]' \| \ X"$ac_file" : 'X\(//\)$' \| \ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || printf "%s\n" X"$ac_file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` as_dir="$ac_dir"; as_fn_mkdir_p ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`printf "%s\n" "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`printf "%s\n" "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix case $ac_mode in :F) # # CONFIG_FILE # case $INSTALL in [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; esac _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # If the template does not know about datarootdir, expand it. # FIXME: This hack should be removed a few years after 2.60. ac_datarootdir_hack=; ac_datarootdir_seen= ac_sed_dataroot=' /datarootdir/ { p q } /@datadir@/p /@docdir@/p /@infodir@/p /@localedir@/p /@mandir@/p' case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in *datarootdir*) ac_datarootdir_seen=yes;; *@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 printf "%s\n" "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_datarootdir_hack=' s&@datadir@&$datadir&g s&@docdir@&$docdir&g s&@infodir@&$infodir&g s&@localedir@&$localedir&g s&@mandir@&$mandir&g s&\\\${datarootdir}&$datarootdir&g' ;; esac _ACEOF # Neutralize VPATH when `$srcdir' = `.'. # Shell code in configure.ac might set extrasub. # FIXME: do we really want to maintain this feature? cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_sed_extra="$ac_vpsub $extrasub _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 :t /@[a-zA-Z_][a-zA-Z_0-9]*@/!b s|@configure_input@|$ac_sed_conf_input|;t t s&@top_builddir@&$ac_top_builddir_sub&;t t s&@top_build_prefix@&$ac_top_build_prefix&;t t s&@srcdir@&$ac_srcdir&;t t s&@abs_srcdir@&$ac_abs_srcdir&;t t s&@top_srcdir@&$ac_top_srcdir&;t t s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t s&@builddir@&$ac_builddir&;t t s&@abs_builddir@&$ac_abs_builddir&;t t s&@abs_top_builddir@&$ac_abs_top_builddir&;t t s&@INSTALL@&$ac_INSTALL&;t t $ac_datarootdir_hack " eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ "$ac_tmp/out"`; test -z "$ac_out"; } && { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&5 printf "%s\n" "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&2;} rm -f "$ac_tmp/stdin" case $ac_file in -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; esac \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; :H) # # CONFIG_HEADER # if test x"$ac_file" != x-; then { printf "%s\n" "/* $configure_input */" >&1 \ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" } >"$ac_tmp/config.h" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 printf "%s\n" "$as_me: $ac_file is unchanged" >&6;} else rm -f "$ac_file" mv "$ac_tmp/config.h" "$ac_file" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 fi else printf "%s\n" "/* $configure_input */" >&1 \ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \ || as_fn_error $? "could not create -" "$LINENO" 5 fi ;; esac done # for ac_tag as_fn_exit 0 _ACEOF ac_clean_files=$ac_clean_files_save test $ac_write_fail = 0 || as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 # configure is writing to config.log, and then calls config.status. # config.status does its own redirection, appending to config.log. # Unfortunately, on DOS this fails, as config.log is still kept open # by configure, so config.status won't be able to write to it; its # output is simply discarded. So we exec the FD to /dev/null, # effectively closing config.log, so it can be properly (re)opened and # appended to by config.status. When coming back to configure, we # need to make the FD available again. if test "$no_create" != yes; then ac_cs_success=: ac_config_status_args= test "$silent" = yes && ac_config_status_args="$ac_config_status_args --quiet" exec 5>/dev/null $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false exec 5>>config.log # Use ||, not &&, to avoid exiting from the if with $? = 1, which # would make configure fail if this is the last instruction. $ac_cs_success || as_fn_exit 1 fi if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 printf "%s\n" "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} fi librecast/libs/libmld/configure.ac000066400000000000000000000051601502456746400175270ustar00rootroot00000000000000# -*- Autoconf -*- # Process this file with autoconf to produce a configure script. AC_PREREQ([2.71]) AC_INIT([mld], [0.0.0], [bugs@librecast.net]) AC_SUBST(PACKAGE_ABIVERS, 0.0) AC_COPYRIGHT(Copyright (c) 2022-2024 Brett Sheffield See COPYING for license details. ) AC_CONFIG_SRCDIR([src/]) AC_CONFIG_HEADERS([src/config.h]) # Checks for programs. AC_PROG_CXX AC_PROG_CC AC_PROG_INSTALL AC_PROG_LN_S AC_CHECK_PROG([testrunner], [lctest], [lctest], [maketest]) AC_SUBST([TESTRUNNER],[$testrunner]) AC_CHECK_PROGS([FALSE], [false], [/usr/bin/env false]) dnl Enable Bloom Filters? AC_ARG_ENABLE([bloom-filters], AS_HELP_STRING([--enable-bloom-filters], [Enable bloom filters])) AS_IF([test "x$enable_bloom_filters" = "xyes"], [ AC_DEFINE([USE_BLOOM_FILTER],[1],[Use bloom filters]) AC_SUBST([VEC_O],["vec.o"]) AC_SUBST([MLD_BLOOM_FILTER], ["#define MLD_BLOOM_FILTER 1"], ["#undef MLD_BLOOM_FILTER"]) ]) if test -f "../../include/librecast.h"; then AC_SUBST([LIBRECAST_CFLAGS], ["-I\$(SOURCEDIR)/include"]) AC_SUBST([LIBMLD], ["-llibrecast"]) AC_DEFINE([HAVE_LIBLIBRECAST]) else AC_SUBST([LIBMLD], ["-lmld"]) fi if test -f "../../src/librecast.c"; then AC_SUBST([LIBRECAST_LDFLAGS], ["-L\$(SOURCEDIR)/src -Wl,-rpath,\$(SOURCEDIR)/src"]) fi # Checks for libraries. AC_CHECK_LIB([dl], [dlsym]) AC_CHECK_LIB([librecast], [lc_ctx_new]) AC_CHECK_LIB([m], [log2]) AC_CHECK_LIB([pthread], [pthread_create]) AC_SEARCH_LIBS([clock_gettime], [rt]) # Checks for functions. AC_CHECK_FUNCS([clock_gettime getpagesize memset socket strerror],, AC_MSG_ERROR([required function missing])) # Checks for header files. AC_CHECK_HEADERS([asm/types.h]) AC_CHECK_HEADERS([fcntl.h]) AC_CHECK_HEADERS([net/bpf.h]) AC_CHECK_HEADERS([netdb.h]) AC_CHECK_HEADERS([netinet/icmp6.h]) AC_CHECK_HEADERS([netinet/in.h]) AC_CHECK_HEADERS([netinet6/ip6_mroute.h], [], [], [ # include # include # include # include ]) AC_CHECK_HEADERS([stdint.h]) AC_CHECK_HEADERS([sys/socket.h sys/time.h]) AC_CHECK_HEADERS([endian.h sys/endian.h libkern/OSByteOrder.h]) # wanted by bloom filter code AC_CHECK_HEADERS([arpa/inet.h]) AC_CHECK_HEADERS([sys/ioctl.h]) AC_CHECK_HEADERS([sys/param.h]) AC_CHECK_HEADERS([unistd.h]) # Checks for typedefs, structures, and compiler characteristics. AC_C_INLINE AC_TYPE_SIZE_T AC_TYPE_SSIZE_T AC_TYPE_UINT64_T AC_TYPE_UINT32_T AC_TYPE_UINT16_T AC_TYPE_UINT8_T # Checks for library functions. AC_CONFIG_FILES([Makefile src/Makefile test/Makefile include/mld.h ]) AC_OUTPUT librecast/libs/libmld/doc/000077500000000000000000000000001502456746400160045ustar00rootroot00000000000000librecast/libs/libmld/doc/mld_free.3000066400000000000000000000000241502456746400176410ustar00rootroot00000000000000.so man3/mld_init.3 librecast/libs/libmld/doc/mld_init.3000066400000000000000000000025271502456746400176750ustar00rootroot00000000000000.TH MLD_INIT 3 2023-08-05 "LIBRECAST" "Librecast Programmer's Manual" .SH NAME mld_init, mld_free \- create and free MLD contexts .SH SYNOPSIS .nf .B #include .PP .BI "mld_t *mld_init(int " "flags" ); .BI "void mld_free(mld_t " "*mld" ); .fi .PP Compile and link with \fI\-lmld\fP. .SH DESCRIPTION .BR mld_init () creates a new MLD context and sets up the environment. Call .BR mld_free (3) when done. .PP .BR mld_free () invalidates and frees a MLD context created with .BR mld_init (3) . .SH RETURN VALUE .BR mld_init () returns a pointer to a .I mld_t handle. On error returns NULL and sets .I errno to indicate the error. .PP The .BR mld_free () function returns no value. .SH ERRORS .BR mld_init () can fail with the following errors: .TP .B ENOMEM Out of memory. Possibly, the application hit the .BR RLIMIT_AS or .BR RLIMIT_DATA limit described in .BR getrlimit (2). .PP .BR mld_init () can also fail with any of the errors for .BR sem_init (3): .TP .B EINVAL .I value exceeds .BR SEM_VALUE_MAX . .TP .B ENOSYS .I pshared is nonzero, but the system does not support process-shared semaphores (see .BR sem_overview (7)). .SH EXAMPLE .SS Program source \& .EX mld_t *mld; mld = mld_init(0); /* your program here */ mld_free(mld); /* free context when done */ .EE .SH SEE ALSO .BR mld_start (3), .BR mld_stop (3), .BR sem_init (3), .BR sem_overview (7) librecast/libs/libmld/doc/mld_start.3000066400000000000000000000040601502456746400200610ustar00rootroot00000000000000.TH MLD_START 3 2023-08-05 "LIBRECAST" "Librecast Programmer's Manual" .SH NAME mld_start, mld_stop \- start and stop MLD processing .SH SYNOPSIS .nf .B #include .PP .BI "mld_t *mld_start(mld_t " *mld ")" .BI "void mld_stop(mld_t " *mld ")" .fi .PP Compile and link with \fI\-lmld\fP. .SH DESCRIPTION .BR mld_start () starts the MLD listening threads and begins processing MLD events. .PP .BR mld_stop (3) stops all MLD processing and cancels and joins the MLD threads. .PP .IR mld can either be a pointer to an .IR mld_t handle returned by .BR mld_init (3) or NULL. If NULL, .BR mld_init (3) will be called to create and return a handle. This will need to be freed by calling .BR mld_free (3) when done (after first calling .BR mld_stop (3)). .PP There are a number of threads started by .BR mld_start (): .TP .B NETLINK detects interface changes and reports them to .BR STATE . .TP .B LISTEN listens for MLD traffic and reports events to .BR STATE . .TP .B TIMER creates jobs for .B STATE to expire MLD records. .TP .B STATE handles all reads and writes to MLD cache, notifies .B WATCH of events. .TP .B WATCH receives events from .B STATE and creates callback threads for watchers. .SH RETURN VALUE .BR mld_start () returns a pointer to a .I mld_t handle. On error returns NULL and sets .I errno to indicate the error. .PP The .BR mld_stop () function returns no value. .SH ERRORS .BR mld_start () can fail with the following errors: .TP .B ENOMEM Out of memory. Possibly, the application hit the .BR RLIMIT_AS or .BR RLIMIT_DATA limit described in .BR getrlimit (2). .PP .BR mld_start() can also fail with the errors for .BR sem_post(3). .SH SEE ALSO .BR mld_init (3), .BR mld_free (3), .BR mld_filter_grp_add (3), .BR mld_filter_grp_cmp (3), .BR mld_filter_grp_del (3), .BR mld_filter_timer_get (3), .BR mld_filter_timer_set (3), .BR mld_filter_timer_set_s (3), .BR mld_wait (3), .BR mld_watch_add (3), .BR mld_watch_arg (3), .BR mld_watch_del (3), .BR mld_watch_flags (3), .BR mld_watch_grp (3), .BR mld_watch_ifx (3), .BR mld_watch_mld (3), .BR mld_watch_tid (3), .BR sem_post(3) librecast/libs/libmld/doc/mld_stop.3000066400000000000000000000000251502456746400177060ustar00rootroot00000000000000.so man3/mld_start.3 librecast/libs/libmld/doc/mld_wait.3000066400000000000000000000035011502456746400176670ustar00rootroot00000000000000.TH MLD_WAIT 3 2023-08-12 "LIBRECAST" "Librecast Programmer's Manual" .SH NAME mld_wait \- wait on an MLD event .SH SYNOPSIS .nf .B #include .PP .BI "int mld_wait(mld_t " *mld ", unsigned int " ifx ", struct in6_addr " *addr ", int " flags ");" .fi .PP Compile and link with \fI\-lmld\fP or \fI\-llibrecast\fP depending on whether you have installed the standalone libmld or liblibrecast (with MLD support). .SH DESCRIPTION The .BR mld_wait () function waits for an MLD event to occur on interface .IR ifx . .PP .IR mld must be a pointer to an .IR mld_t initialized with .BR mld_init (3). .PP .IR addr can either be NULL, or it must be a pointer to a .I struct in6_addr containing a valid IPv6 multicast address. If NULL, .BR mld_wait () will match events for any multicast address. .PP The .IR flags argument is the bitwise OR of zero or more of the following flags: .TP .B MLD_DONTWAIT Enables nonblocking operation; if the operation would block, -1 is returned and .IR errno is set to .IR EWOULDBLOCK . .SH RETURN VALUE .BR mld_wait () returns zero on success or -1 on failure, with .IR errno set to indicate the error. .SH ERRORS .BR mld_wait () can fail with the following errors: .TP .B EWOULDBLOCK Nonblocking operation was requested and the requested operation would block. .TP .B EINTR The operation was interupted by a signal. .TP .B ENOMEM Out of memory. Possibly, the application hit the .BR RLIMIT_AS or .BR RLIMIT_DATA limit described in .BR getrlimit (2). .PP .BR mld_init () can also fail with any of the errors for .BR sem_init (3): .TP .B EINVAL .I value exceeds .BR SEM_VALUE_MAX . .TP .B ENOSYS .I pshared is nonzero, but the system does not support process-shared semaphores (see .BR sem_overview (7)). .SH SEE ALSO .BR mld_init (3), .BR mld_free (3), .BR mld_start (3), .BR mld_stop (3), .BR sem_init (3), .BR sem_overview (7) librecast/libs/libmld/include/000077500000000000000000000000001502456746400166625ustar00rootroot00000000000000librecast/libs/libmld/include/.gitignore000066400000000000000000000000061502456746400206460ustar00rootroot00000000000000mld.h librecast/libs/libmld/include/mld.h.in000066400000000000000000000127161502456746400202230ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2020-2025 Brett Sheffield */ #ifndef _MLD_H #define _MLD_H 1 /* * MLDv2 library * * Threads: * - NETLINK - detects interface changes and reports them to STATE * - LISTEN - listens for MLD traffic and reports events to STATE * - TIMER - creates jobs for STATE to expire MLD records * - STATE - handles all reads and writes to MLD cache, notifies WATCH of events * - WATCH - receives events from STATE and creates callback threads for watchers */ #include #include #include #include #include #include #include @MLD_BLOOM_FILTER@ #ifdef MLD_BLOOM_FILTER # include # define BLOOM_SZ 16777216 # define BLOOM_VECTORS BLOOM_SZ / VECTOR_BITS # define BLOOM_HASHES 8 /* optimal = LOG2(BLOOM_SZ / ENTRIES) */ #endif #define MLD_TIMEOUT 125 /* seconds before MLD record expires */ #define MLD_TIMER_INTERVAL 1 /* length of timer tick in seconds */ #define IPV6_BYTES 16 /* See RFC 9777 */ /* MALI = Multicast Address Listening Interval */ /* LLQT = Last Listener Query Time */ #define MLD2_ROBUSTNESS 2 /* 9.14.1. Robustness Variable */ _Static_assert(MLD2_ROBUSTNESS <= 0x7, "QRV > 3 bits"); #define MLD2_ALL_NODES "ff02::1" /* all MLDv2-capable routers */ #define MLD2_CAPABLE_ROUTERS "ff02::16" /* all MLDv2-capable routers */ #define MLD2_LISTENER_REPORT 143 /* Multicast Listener Report messages */ #define MLD2_QI MLD_TIMEOUT /* Query Interval */ #define MLD2_QRI 10000 /* Query Response Interval (RFC suggests 10000 = 10s) */ /* RFC 9777 says MALI MUST be: * [Robustness Variable] times [Query Interval]) plus 2 times [Query Response Interval] */ #define MLD2_MALI MLD2_ROBUSTNESS * MLD2_QI + MLD2_QRI * 2 /* 9.5. Other Querier Present Timeout * ([Robustness Variable] times ([Query Interval]) plus (one half of [Query Response Interval]).*/ #define MLD2_OTHER_QUERIER_TIMEOUT MLD2_ROBUSTNESS * MLD2_QI + MLD2_QRI / 2000 /* Current State Record */ #define MODE_IS_INCLUDE 1 #define MODE_IS_EXCLUDE 2 /* Filter Mode Change Record */ #define CHANGE_TO_INCLUDE_MODE 3 #define CHANGE_TO_EXCLUDE_MODE 4 /* Source List Change Record */ #define ALLOW_NEW_SOURCES 5 #define BLOCK_OLD_SOURCES 6 /* 9.14.1. Robustness Variable */ #define MLD2_ROBUSTNESS 2 /* flags */ enum { MLD_DONTWAIT = 1 }; /* Event Types */ typedef enum { MLD_EVENT_JOIN = 1, MLD_EVENT_PART = 2, MLD_EVENT_IFUP = 4, MLD_EVENT_IFDOWN = 8, MLD_EVENT_MAX } mld_event_type_t; #define MLD_EVENT_ALL ((MLD_EVENT_MAX - 1) << 1) - 1 /* port (or service) to use for MLD event notifications */ #define MLD_EVENT_SERV 4242 #define aitoin6(ai) &(((struct sockaddr_in6 *)ai->ai_addr)->sin6_addr) typedef struct mld_s mld_t; typedef struct mld_addr_rec_s mld_addr_rec_t; typedef struct mld_grp_list_s mld_grp_list_t; typedef struct mld_query_msg_s mld_query_msg_t; typedef struct mld_grp_s mld_grp_t; typedef struct mld_msg_s mld_msg_t; typedef struct mld_iface_s mld_iface_t; typedef struct mld_txn_s mld_txn_t; typedef struct mld_watch_s mld_watch_t; #ifdef MLD_BLOOM_FILTER typedef struct mld_filter_s mld_filter_t; typedef struct mld_timerjob_s mld_timerjob_t; #endif struct mld_grp_s { mld_t *mld; unsigned int iface; struct in6_addr *grp; }; /* set loglevel */ void mld_loglevel_set(int level); /* initialize / free state machine */ mld_t *mld_init(int flags); /* free MLD objects */ void mld_free(mld_t *mld); /* start MLD snooping */ mld_t *mld_start(mld_t *mld); /* stop MLD snooping */ void mld_stop(mld_t *mld); /* return true (1) if filter contains addr, false (0) if not, -1 on error */ int mld_filter_grp_cmp(mld_t *mld, unsigned int ifx, struct in6_addr *addr); /* add group address to interface filter * return result of mld_filter_grp_cmp() before adding. -1 on error */ int mld_filter_grp_add(mld_t *mld, unsigned int ifx, struct in6_addr *addr); /* delete group address from interface filter */ int mld_filter_grp_del(mld_t *mld, unsigned int ifx, struct in6_addr *addr); /* get timer for group on interface */ int mld_filter_timer_get(mld_t *mld, unsigned int ifx, struct in6_addr *addr, struct timespec *ts); /* set timer for group on interface */ int mld_filter_timer_set(mld_t *mld, unsigned int ifx, struct in6_addr *addr, struct timespec *ts); /* set timer for group on interface to now + s seconds */ int mld_filter_timer_set_s(mld_t *mld, unsigned int ifx, struct in6_addr *addr, int s); /* add watch */ mld_watch_t *mld_watch_add(mld_t *mld, unsigned int ifx, struct in6_addr *addr, void (*f)(mld_watch_t *), void *arg, int flags); /* delete watch */ void mld_watch_del(mld_watch_t *watch); mld_t *mld_watch_mld(mld_watch_t *watch); unsigned int mld_watch_ifx(mld_watch_t *watch); struct in6_addr *mld_watch_grp(mld_watch_t *watch); void *mld_watch_arg(mld_watch_t *watch); pthread_t mld_watch_tid(mld_watch_t *watch); int mld_watch_flags(mld_watch_t *watch); /* block until notification received for addr on interface index ifx. If ifx is * zero, all interfaces are watched. Returns 0 on success, or -1 on error and * errno is set to indicate the error. * * The flags argument is formed by ORing one or more of the following values: * * MLD_DONTWAIT * Enables nonblocking operation; if the operation would block, the call * fails with the error EWOULDBLOCK.*/ int mld_wait(mld_t *mld, unsigned int ifx, struct in6_addr *addr, int flags); #endif /* _MLD_H */ librecast/libs/libmld/install-sh000066400000000000000000001051161502456746400172440ustar00rootroot00000000000000#! /bin/sh # Configuration validation subroutine script. # Copyright 1992-2022 Free Software Foundation, Inc. # shellcheck disable=SC2006,SC2268 # see below for rationale timestamp='2022-01-03' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 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 . # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that # program. This Exception is an additional permission under section 7 # of the GNU General Public License, version 3 ("GPLv3"). # Please send patches to . # # Configuration subroutine to validate and canonicalize a configuration type. # Supply the specified configuration type as an argument. # If it is invalid, we print an error message on stderr and exit with code 1. # Otherwise, we print the canonical config type on stdout and succeed. # You can get the latest version of this script from: # https://git.savannah.gnu.org/cgit/config.git/plain/config.sub # This file is supposed to be the same for all GNU packages # and recognize all the CPU types, system types and aliases # that are meaningful with *any* GNU software. # Each package is responsible for reporting which valid configurations # it does not support. The user should be able to distinguish # a failure to support a valid configuration from a meaningless # configuration. # The goal of this file is to map all the various variations of a given # machine specification into a single specification in the form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM # or in some cases, the newer four-part form: # CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM # It is wrong to echo any other type of specification. # The "shellcheck disable" line above the timestamp inhibits complaints # about features and limitations of the classic Bourne shell that were # superseded or lifted in POSIX. However, this script identifies a wide # variety of pre-POSIX systems that do not have POSIX shells at all, and # even some reasonably current systems (Solaris 10 as case-in-point) still # have a pre-POSIX /bin/sh. me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] CPU-MFR-OPSYS or ALIAS Canonicalize a configuration name. Options: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.sub ($timestamp) Copyright 1992-2022 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit ;; --version | -v ) echo "$version" ; exit ;; --help | --h* | -h ) echo "$usage"; exit ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" >&2 exit 1 ;; *local*) # First pass through any local machine types. echo "$1" exit ;; * ) break ;; esac done case $# in 0) echo "$me: missing argument$help" >&2 exit 1;; 1) ;; *) echo "$me: too many arguments$help" >&2 exit 1;; esac # Split fields of configuration type # shellcheck disable=SC2162 saved_IFS=$IFS IFS="-" read field1 field2 field3 field4 <&2 exit 1 ;; *-*-*-*) basic_machine=$field1-$field2 basic_os=$field3-$field4 ;; *-*-*) # Ambiguous whether COMPANY is present, or skipped and KERNEL-OS is two # parts maybe_os=$field2-$field3 case $maybe_os in nto-qnx* | linux-* | uclinux-uclibc* \ | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* \ | netbsd*-eabi* | kopensolaris*-gnu* | cloudabi*-eabi* \ | storm-chaos* | os2-emx* | rtmk-nova*) basic_machine=$field1 basic_os=$maybe_os ;; android-linux) basic_machine=$field1-unknown basic_os=linux-android ;; *) basic_machine=$field1-$field2 basic_os=$field3 ;; esac ;; *-*) # A lone config we happen to match not fitting any pattern case $field1-$field2 in decstation-3100) basic_machine=mips-dec basic_os= ;; *-*) # Second component is usually, but not always the OS case $field2 in # Prevent following clause from handling this valid os sun*os*) basic_machine=$field1 basic_os=$field2 ;; zephyr*) basic_machine=$field1-unknown basic_os=$field2 ;; # Manufacturers dec* | mips* | sequent* | encore* | pc533* | sgi* | sony* \ | att* | 7300* | 3300* | delta* | motorola* | sun[234]* \ | unicom* | ibm* | next | hp | isi* | apollo | altos* \ | convergent* | ncr* | news | 32* | 3600* | 3100* \ | hitachi* | c[123]* | convex* | sun | crds | omron* | dg \ | ultra | tti* | harris | dolphin | highlevel | gould \ | cbm | ns | masscomp | apple | axis | knuth | cray \ | microblaze* | sim | cisco \ | oki | wec | wrs | winbond) basic_machine=$field1-$field2 basic_os= ;; *) basic_machine=$field1 basic_os=$field2 ;; esac ;; esac ;; *) # Convert single-component short-hands not valid as part of # multi-component configurations. case $field1 in 386bsd) basic_machine=i386-pc basic_os=bsd ;; a29khif) basic_machine=a29k-amd basic_os=udi ;; adobe68k) basic_machine=m68010-adobe basic_os=scout ;; alliant) basic_machine=fx80-alliant basic_os= ;; altos | altos3068) basic_machine=m68k-altos basic_os= ;; am29k) basic_machine=a29k-none basic_os=bsd ;; amdahl) basic_machine=580-amdahl basic_os=sysv ;; amiga) basic_machine=m68k-unknown basic_os= ;; amigaos | amigados) basic_machine=m68k-unknown basic_os=amigaos ;; amigaunix | amix) basic_machine=m68k-unknown basic_os=sysv4 ;; apollo68) basic_machine=m68k-apollo basic_os=sysv ;; apollo68bsd) basic_machine=m68k-apollo basic_os=bsd ;; aros) basic_machine=i386-pc basic_os=aros ;; aux) basic_machine=m68k-apple basic_os=aux ;; balance) basic_machine=ns32k-sequent basic_os=dynix ;; blackfin) basic_machine=bfin-unknown basic_os=linux ;; cegcc) basic_machine=arm-unknown basic_os=cegcc ;; convex-c1) basic_machine=c1-convex basic_os=bsd ;; convex-c2) basic_machine=c2-convex basic_os=bsd ;; convex-c32) basic_machine=c32-convex basic_os=bsd ;; convex-c34) basic_machine=c34-convex basic_os=bsd ;; convex-c38) basic_machine=c38-convex basic_os=bsd ;; cray) basic_machine=j90-cray basic_os=unicos ;; crds | unos) basic_machine=m68k-crds basic_os= ;; da30) basic_machine=m68k-da30 basic_os= ;; decstation | pmax | pmin | dec3100 | decstatn) basic_machine=mips-dec basic_os= ;; delta88) basic_machine=m88k-motorola basic_os=sysv3 ;; dicos) basic_machine=i686-pc basic_os=dicos ;; djgpp) basic_machine=i586-pc basic_os=msdosdjgpp ;; ebmon29k) basic_machine=a29k-amd basic_os=ebmon ;; es1800 | OSE68k | ose68k | ose | OSE) basic_machine=m68k-ericsson basic_os=ose ;; gmicro) basic_machine=tron-gmicro basic_os=sysv ;; go32) basic_machine=i386-pc basic_os=go32 ;; h8300hms) basic_machine=h8300-hitachi basic_os=hms ;; h8300xray) basic_machine=h8300-hitachi basic_os=xray ;; h8500hms) basic_machine=h8500-hitachi basic_os=hms ;; harris) basic_machine=m88k-harris basic_os=sysv3 ;; hp300 | hp300hpux) basic_machine=m68k-hp basic_os=hpux ;; hp300bsd) basic_machine=m68k-hp basic_os=bsd ;; hppaosf) basic_machine=hppa1.1-hp basic_os=osf ;; hppro) basic_machine=hppa1.1-hp basic_os=proelf ;; i386mach) basic_machine=i386-mach basic_os=mach ;; isi68 | isi) basic_machine=m68k-isi basic_os=sysv ;; m68knommu) basic_machine=m68k-unknown basic_os=linux ;; magnum | m3230) basic_machine=mips-mips basic_os=sysv ;; merlin) basic_machine=ns32k-utek basic_os=sysv ;; mingw64) basic_machine=x86_64-pc basic_os=mingw64 ;; mingw32) basic_machine=i686-pc basic_os=mingw32 ;; mingw32ce) basic_machine=arm-unknown basic_os=mingw32ce ;; monitor) basic_machine=m68k-rom68k basic_os=coff ;; morphos) basic_machine=powerpc-unknown basic_os=morphos ;; moxiebox) basic_machine=moxie-unknown basic_os=moxiebox ;; msdos) basic_machine=i386-pc basic_os=msdos ;; msys) basic_machine=i686-pc basic_os=msys ;; mvs) basic_machine=i370-ibm basic_os=mvs ;; nacl) basic_machine=le32-unknown basic_os=nacl ;; ncr3000) basic_machine=i486-ncr basic_os=sysv4 ;; netbsd386) basic_machine=i386-pc basic_os=netbsd ;; netwinder) basic_machine=armv4l-rebel basic_os=linux ;; news | news700 | news800 | news900) basic_machine=m68k-sony basic_os=newsos ;; news1000) basic_machine=m68030-sony basic_os=newsos ;; necv70) basic_machine=v70-nec basic_os=sysv ;; nh3000) basic_machine=m68k-harris basic_os=cxux ;; nh[45]000) basic_machine=m88k-harris basic_os=cxux ;; nindy960) basic_machine=i960-intel basic_os=nindy ;; mon960) basic_machine=i960-intel basic_os=mon960 ;; nonstopux) basic_machine=mips-compaq basic_os=nonstopux ;; os400) basic_machine=powerpc-ibm basic_os=os400 ;; OSE68000 | ose68000) basic_machine=m68000-ericsson basic_os=ose ;; os68k) basic_machine=m68k-none basic_os=os68k ;; paragon) basic_machine=i860-intel basic_os=osf ;; parisc) basic_machine=hppa-unknown basic_os=linux ;; psp) basic_machine=mipsallegrexel-sony basic_os=psp ;; pw32) basic_machine=i586-unknown basic_os=pw32 ;; rdos | rdos64) basic_machine=x86_64-pc basic_os=rdos ;; rdos32) basic_machine=i386-pc basic_os=rdos ;; rom68k) basic_machine=m68k-rom68k basic_os=coff ;; sa29200) basic_machine=a29k-amd basic_os=udi ;; sei) basic_machine=mips-sei basic_os=seiux ;; sequent) basic_machine=i386-sequent basic_os= ;; sps7) basic_machine=m68k-bull basic_os=sysv2 ;; st2000) basic_machine=m68k-tandem basic_os= ;; stratus) basic_machine=i860-stratus basic_os=sysv4 ;; sun2) basic_machine=m68000-sun basic_os= ;; sun2os3) basic_machine=m68000-sun basic_os=sunos3 ;; sun2os4) basic_machine=m68000-sun basic_os=sunos4 ;; sun3) basic_machine=m68k-sun basic_os= ;; sun3os3) basic_machine=m68k-sun basic_os=sunos3 ;; sun3os4) basic_machine=m68k-sun basic_os=sunos4 ;; sun4) basic_machine=sparc-sun basic_os= ;; sun4os3) basic_machine=sparc-sun basic_os=sunos3 ;; sun4os4) basic_machine=sparc-sun basic_os=sunos4 ;; sun4sol2) basic_machine=sparc-sun basic_os=solaris2 ;; sun386 | sun386i | roadrunner) basic_machine=i386-sun basic_os= ;; sv1) basic_machine=sv1-cray basic_os=unicos ;; symmetry) basic_machine=i386-sequent basic_os=dynix ;; t3e) basic_machine=alphaev5-cray basic_os=unicos ;; t90) basic_machine=t90-cray basic_os=unicos ;; toad1) basic_machine=pdp10-xkl basic_os=tops20 ;; tpf) basic_machine=s390x-ibm basic_os=tpf ;; udi29k) basic_machine=a29k-amd basic_os=udi ;; ultra3) basic_machine=a29k-nyu basic_os=sym1 ;; v810 | necv810) basic_machine=v810-nec basic_os=none ;; vaxv) basic_machine=vax-dec basic_os=sysv ;; vms) basic_machine=vax-dec basic_os=vms ;; vsta) basic_machine=i386-pc basic_os=vsta ;; vxworks960) basic_machine=i960-wrs basic_os=vxworks ;; vxworks68) basic_machine=m68k-wrs basic_os=vxworks ;; vxworks29k) basic_machine=a29k-wrs basic_os=vxworks ;; xbox) basic_machine=i686-pc basic_os=mingw32 ;; ymp) basic_machine=ymp-cray basic_os=unicos ;; *) basic_machine=$1 basic_os= ;; esac ;; esac # Decode 1-component or ad-hoc basic machines case $basic_machine in # Here we handle the default manufacturer of certain CPU types. It is in # some cases the only manufacturer, in others, it is the most popular. w89k) cpu=hppa1.1 vendor=winbond ;; op50n) cpu=hppa1.1 vendor=oki ;; op60c) cpu=hppa1.1 vendor=oki ;; ibm*) cpu=i370 vendor=ibm ;; orion105) cpu=clipper vendor=highlevel ;; mac | mpw | mac-mpw) cpu=m68k vendor=apple ;; pmac | pmac-mpw) cpu=powerpc vendor=apple ;; # Recognize the various machine names and aliases which stand # for a CPU type and a company and sometimes even an OS. 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) cpu=m68000 vendor=att ;; 3b*) cpu=we32k vendor=att ;; bluegene*) cpu=powerpc vendor=ibm basic_os=cnk ;; decsystem10* | dec10*) cpu=pdp10 vendor=dec basic_os=tops10 ;; decsystem20* | dec20*) cpu=pdp10 vendor=dec basic_os=tops20 ;; delta | 3300 | motorola-3300 | motorola-delta \ | 3300-motorola | delta-motorola) cpu=m68k vendor=motorola ;; dpx2*) cpu=m68k vendor=bull basic_os=sysv3 ;; encore | umax | mmax) cpu=ns32k vendor=encore ;; elxsi) cpu=elxsi vendor=elxsi basic_os=${basic_os:-bsd} ;; fx2800) cpu=i860 vendor=alliant ;; genix) cpu=ns32k vendor=ns ;; h3050r* | hiux*) cpu=hppa1.1 vendor=hitachi basic_os=hiuxwe2 ;; hp3k9[0-9][0-9] | hp9[0-9][0-9]) cpu=hppa1.0 vendor=hp ;; hp9k2[0-9][0-9] | hp9k31[0-9]) cpu=m68000 vendor=hp ;; hp9k3[2-9][0-9]) cpu=m68k vendor=hp ;; hp9k6[0-9][0-9] | hp6[0-9][0-9]) cpu=hppa1.0 vendor=hp ;; hp9k7[0-79][0-9] | hp7[0-79][0-9]) cpu=hppa1.1 vendor=hp ;; hp9k78[0-9] | hp78[0-9]) # FIXME: really hppa2.0-hp cpu=hppa1.1 vendor=hp ;; hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) # FIXME: really hppa2.0-hp cpu=hppa1.1 vendor=hp ;; hp9k8[0-9][13679] | hp8[0-9][13679]) cpu=hppa1.1 vendor=hp ;; hp9k8[0-9][0-9] | hp8[0-9][0-9]) cpu=hppa1.0 vendor=hp ;; i*86v32) cpu=`echo "$1" | sed -e 's/86.*/86/'` vendor=pc basic_os=sysv32 ;; i*86v4*) cpu=`echo "$1" | sed -e 's/86.*/86/'` vendor=pc basic_os=sysv4 ;; i*86v) cpu=`echo "$1" | sed -e 's/86.*/86/'` vendor=pc basic_os=sysv ;; i*86sol2) cpu=`echo "$1" | sed -e 's/86.*/86/'` vendor=pc basic_os=solaris2 ;; j90 | j90-cray) cpu=j90 vendor=cray basic_os=${basic_os:-unicos} ;; iris | iris4d) cpu=mips vendor=sgi case $basic_os in irix*) ;; *) basic_os=irix4 ;; esac ;; miniframe) cpu=m68000 vendor=convergent ;; *mint | mint[0-9]* | *MiNT | *MiNT[0-9]*) cpu=m68k vendor=atari basic_os=mint ;; news-3600 | risc-news) cpu=mips vendor=sony basic_os=newsos ;; next | m*-next) cpu=m68k vendor=next case $basic_os in openstep*) ;; nextstep*) ;; ns2*) basic_os=nextstep2 ;; *) basic_os=nextstep3 ;; esac ;; np1) cpu=np1 vendor=gould ;; op50n-* | op60c-*) cpu=hppa1.1 vendor=oki basic_os=proelf ;; pa-hitachi) cpu=hppa1.1 vendor=hitachi basic_os=hiuxwe2 ;; pbd) cpu=sparc vendor=tti ;; pbb) cpu=m68k vendor=tti ;; pc532) cpu=ns32k vendor=pc532 ;; pn) cpu=pn vendor=gould ;; power) cpu=power vendor=ibm ;; ps2) cpu=i386 vendor=ibm ;; rm[46]00) cpu=mips vendor=siemens ;; rtpc | rtpc-*) cpu=romp vendor=ibm ;; sde) cpu=mipsisa32 vendor=sde basic_os=${basic_os:-elf} ;; simso-wrs) cpu=sparclite vendor=wrs basic_os=vxworks ;; tower | tower-32) cpu=m68k vendor=ncr ;; vpp*|vx|vx-*) cpu=f301 vendor=fujitsu ;; w65) cpu=w65 vendor=wdc ;; w89k-*) cpu=hppa1.1 vendor=winbond basic_os=proelf ;; none) cpu=none vendor=none ;; leon|leon[3-9]) cpu=sparc vendor=$basic_machine ;; leon-*|leon[3-9]-*) cpu=sparc vendor=`echo "$basic_machine" | sed 's/-.*//'` ;; *-*) # shellcheck disable=SC2162 saved_IFS=$IFS IFS="-" read cpu vendor <&2 exit 1 ;; esac ;; esac # Here we canonicalize certain aliases for manufacturers. case $vendor in digital*) vendor=dec ;; commodore*) vendor=cbm ;; *) ;; esac # Decode manufacturer-specific aliases for certain operating systems. if test x$basic_os != x then # First recognize some ad-hoc cases, or perhaps split kernel-os, or else just # set os. case $basic_os in gnu/linux*) kernel=linux os=`echo "$basic_os" | sed -e 's|gnu/linux|gnu|'` ;; os2-emx) kernel=os2 os=`echo "$basic_os" | sed -e 's|os2-emx|emx|'` ;; nto-qnx*) kernel=nto os=`echo "$basic_os" | sed -e 's|nto-qnx|qnx|'` ;; *-*) # shellcheck disable=SC2162 saved_IFS=$IFS IFS="-" read kernel os <&2 exit 1 ;; esac # As a final step for OS-related things, validate the OS-kernel combination # (given a valid OS), if there is a kernel. case $kernel-$os in linux-gnu* | linux-dietlibc* | linux-android* | linux-newlib* \ | linux-musl* | linux-relibc* | linux-uclibc* ) ;; uclinux-uclibc* ) ;; -dietlibc* | -newlib* | -musl* | -relibc* | -uclibc* ) # These are just libc implementations, not actual OSes, and thus # require a kernel. echo "Invalid configuration \`$1': libc \`$os' needs explicit kernel." 1>&2 exit 1 ;; kfreebsd*-gnu* | kopensolaris*-gnu*) ;; vxworks-simlinux | vxworks-simwindows | vxworks-spe) ;; nto-qnx*) ;; os2-emx) ;; *-eabi* | *-gnueabi*) ;; -*) # Blank kernel with real OS is always fine. ;; *-*) echo "Invalid configuration \`$1': Kernel \`$kernel' not known to work with OS \`$os'." 1>&2 exit 1 ;; esac # Here we handle the case where we know the os, and the CPU type, but not the # manufacturer. We pick the logical manufacturer. case $vendor in unknown) case $cpu-$os in *-riscix*) vendor=acorn ;; *-sunos*) vendor=sun ;; *-cnk* | *-aix*) vendor=ibm ;; *-beos*) vendor=be ;; *-hpux*) vendor=hp ;; *-mpeix*) vendor=hp ;; *-hiux*) vendor=hitachi ;; *-unos*) vendor=crds ;; *-dgux*) vendor=dg ;; *-luna*) vendor=omron ;; *-genix*) vendor=ns ;; *-clix*) vendor=intergraph ;; *-mvs* | *-opened*) vendor=ibm ;; *-os400*) vendor=ibm ;; s390-* | s390x-*) vendor=ibm ;; *-ptx*) vendor=sequent ;; *-tpf*) vendor=ibm ;; *-vxsim* | *-vxworks* | *-windiss*) vendor=wrs ;; *-aux*) vendor=apple ;; *-hms*) vendor=hitachi ;; *-mpw* | *-macos*) vendor=apple ;; *-*mint | *-mint[0-9]* | *-*MiNT | *-MiNT[0-9]*) vendor=atari ;; *-vos*) vendor=stratus ;; esac ;; esac echo "$cpu-$vendor-${kernel:+$kernel-}$os" exit # Local variables: # eval: (add-hook 'before-save-hook 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: librecast/libs/libmld/src/000077500000000000000000000000001502456746400160265ustar00rootroot00000000000000librecast/libs/libmld/src/Makefile.in000066400000000000000000000042451502456746400201000ustar00rootroot00000000000000# SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only # Copyright (c) 2022-2023 Brett Sheffield SHELL = /bin/sh .SUFFIXES: .SUFFIXES: .c .o CC = @CC@ CFLAGS = @CFLAGS@ CPPFLAGS = @CPPFLAGS@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ LDFLAGS = @LDFLAGS@ LDLIBS = @LIBS@ PACKAGE = @PACKAGE_NAME@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PROGRAM = @PACKAGE_NAME@ SHELL = @SHELL@ bindir = @bindir@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ exec_prefix = @exec_prefix@ mandir = @mandir@ prefix = @prefix@ srcdir = @srcdir@ LIBNAME := @PACKAGE_NAME@ VERSION := @PACKAGE_VERSION@ ABIVERS := @PACKAGE_ABIVERS@ .SUFFIXES: .SUFFIXES: .c .o CFLAGS += -fPIC CFLAGS += -I. -I../include HEADERS = ../include/$(LIBNAME).h $(LIBNAME)_pvt.h $(sort $(wildcard ../include/$(LIBNAME)/*.h)) INSTALL ?= install LDCONFIG ?= ldconfig LDLIBS := @LIBS@ INSTALL_DATA := $(INSTALL) -m 644 PREFIX ?= @prefix@ LIBDIR := $(DESTDIR)$(PREFIX)/lib INCLUDEDIR := $(DESTDIR)$(PREFIX)/include OBJECTS := job.o log.o mld.o misc.o @VEC_O@ ifeq ($(UNAME),Darwin) SOFILE := lib$(LIBNAME).dylib SOOPT := -install_name else SOFILE := lib$(LIBNAME).so SOOPT := -soname endif STATIC := lib$(LIBNAME).a ABIFILE := $(SOFILE).$(ABIVERS) MAJFILE := $(SOFILE).$(SOMAJOR) all: $(SOFILE) $(STATIC) $(SOFILE): $(OBJECTS) $(CC) $(CFLAGS) -shared $(LDFLAGS) -Wl,$(SOOPT),$(ABIFILE) -o $@ $^ $(LDLIBS) ln -sf $@ $(ABIFILE) # required for tests $(STATIC): $(OBJECTS) $(AR) rcs $@ $^ %.o: %.c %.h $(HEADERS) install: $(SOFILE) $(INSTALL) -d $(LIBDIR) $(INSTALL) -d $(INCLUDEDIR) $(INSTALL_DATA) $(SOFILE) $(LIBDIR)/$(ABIFILE) cp -r ../include/*.h $(INCLUDEDIR) ln -sf $(ABIFILE) $(LIBDIR)/$(SOFILE) ln -sf $(ABIFILE) $(LIBDIR)/$(MAJFILE) .PHONY: clean realclean uninstall uninstall: cd $(LIBDIR) && $(RM) $(SOFILE) $(ABIFILE) $(MAJFILE) $(RM) $(INCLUDEDIR)/mld.h clean: $(RM) *.o $(SOFILE) $(ABIFILE) $(STATIC) realclean: clean $(RM) Makefile config.h librecast/libs/libmld/src/config.h.in000066400000000000000000000121561502456746400200560ustar00rootroot00000000000000/* src/config.h.in. Generated from configure.ac by autoheader. */ /* Define to 1 if you have the header file. */ #undef HAVE_ARPA_INET_H /* Define to 1 if you have the header file. */ #undef HAVE_ASM_TYPES_H /* Define to 1 if you have the `clock_gettime' function. */ #undef HAVE_CLOCK_GETTIME /* Define to 1 if you have the header file. */ #undef HAVE_ENDIAN_H /* Define to 1 if you have the header file. */ #undef HAVE_FCNTL_H /* Define to 1 if you have the `getpagesize' function. */ #undef HAVE_GETPAGESIZE /* Define to 1 if you have the header file. */ #undef HAVE_INTTYPES_H /* Define to 1 if you have the `dl' library (-ldl). */ #undef HAVE_LIBDL /* Define to 1 if you have the header file. */ #undef HAVE_LIBKERN_OSBYTEORDER_H /* Define to 1 if you have the `librecast' library (-llibrecast). */ #undef HAVE_LIBLIBRECAST /* Define to 1 if you have the `m' library (-lm). */ #undef HAVE_LIBM /* Define to 1 if you have the `pthread' library (-lpthread). */ #undef HAVE_LIBPTHREAD /* Define to 1 if you have the `memset' function. */ #undef HAVE_MEMSET /* Define to 1 if you have the header file. */ #undef HAVE_NETDB_H /* Define to 1 if you have the header file. */ #undef HAVE_NETINET6_IP6_MROUTE_H /* Define to 1 if you have the header file. */ #undef HAVE_NETINET_ICMP6_H /* Define to 1 if you have the header file. */ #undef HAVE_NETINET_IN_H /* Define to 1 if you have the header file. */ #undef HAVE_NET_BPF_H /* Define to 1 if you have the `socket' function. */ #undef HAVE_SOCKET /* Define to 1 if you have the header file. */ #undef HAVE_STDINT_H /* Define to 1 if you have the header file. */ #undef HAVE_STDIO_H /* Define to 1 if you have the header file. */ #undef HAVE_STDLIB_H /* Define to 1 if you have the `strerror' function. */ #undef HAVE_STRERROR /* Define to 1 if you have the header file. */ #undef HAVE_STRINGS_H /* Define to 1 if you have the header file. */ #undef HAVE_STRING_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_ENDIAN_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_IOCTL_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_PARAM_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_SOCKET_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_STAT_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_TIME_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_TYPES_H /* Define to 1 if you have the header file. */ #undef HAVE_UNISTD_H /* Define to the address where bug reports for this package should be sent. */ #undef PACKAGE_BUGREPORT /* Define to the full name of this package. */ #undef PACKAGE_NAME /* Define to the full name and version of this package. */ #undef PACKAGE_STRING /* Define to the one symbol short name of this package. */ #undef PACKAGE_TARNAME /* Define to the home page for this package. */ #undef PACKAGE_URL /* Define to the version of this package. */ #undef PACKAGE_VERSION /* Define to 1 if all of the C90 standard headers exist (not just the ones required in a freestanding environment). This macro is provided for backward compatibility; new code need not use it. */ #undef STDC_HEADERS /* Use bloom filters */ #undef USE_BLOOM_FILTER /* Define for Solaris 2.5.1 so the uint32_t typedef from , , or is not used. If the typedef were allowed, the #define below would cause a syntax error. */ #undef _UINT32_T /* Define for Solaris 2.5.1 so the uint64_t typedef from , , or is not used. If the typedef were allowed, the #define below would cause a syntax error. */ #undef _UINT64_T /* Define for Solaris 2.5.1 so the uint8_t typedef from , , or is not used. If the typedef were allowed, the #define below would cause a syntax error. */ #undef _UINT8_T /* Define to `__inline__' or `__inline' if that's what the C compiler calls it, or to nothing if 'inline' is not supported under any name. */ #ifndef __cplusplus #undef inline #endif /* Define to `unsigned int' if does not define. */ #undef size_t /* Define to `int' if does not define. */ #undef ssize_t /* Define to the type of an unsigned integer type of width exactly 16 bits if such a type exists and the standard includes do not define it. */ #undef uint16_t /* Define to the type of an unsigned integer type of width exactly 32 bits if such a type exists and the standard includes do not define it. */ #undef uint32_t /* Define to the type of an unsigned integer type of width exactly 64 bits if such a type exists and the standard includes do not define it. */ #undef uint64_t /* Define to the type of an unsigned integer type of width exactly 8 bits if such a type exists and the standard includes do not define it. */ #undef uint8_t librecast/libs/libmld/src/job.c000066400000000000000000000070241502456746400167470ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2020-2023 Brett Sheffield */ #include #include #include #include "job.h" #include "log.h" #define aload(x) __atomic_load_n((x), __ATOMIC_ACQUIRE) #define astor(x, y) __atomic_store_n((x),(y), __ATOMIC_RELEASE) job_t *job_shift(job_queue_t *q) { job_t *job; if (sem_wait(&q->lock) == -1) return NULL; if ((job = aload(&q->next))) { job_t *next = aload(&job->next); astor(&q->next, next); if (!next) astor(&q->last, NULL); } sem_post(&q->lock); return job; } static job_t *job_shiftlock(job_queue_t *q, int(*lockf)(sem_t *sem)) { job_t *job = NULL; if (!lockf(&q->jobs)) { job = job_shift(q); } return job; } job_t *job_trywait(job_queue_t *q) { return job_shiftlock(q, &sem_trywait); } job_t *job_wait(job_queue_t *q) { return job_shiftlock(q, &sem_wait); } job_t *job_new(void *(*f)(void *), void *arg, size_t len, void (*callback)(void *), int flags) { job_t *job = calloc(1, sizeof(job_t)); if (!job) return NULL; job->f = f; if ((flags & JOB_COPY) == JOB_COPY) { job->arg = malloc(len); if (!job->arg) goto exit_0; memcpy(job->arg, arg, len); } else { job->arg = arg; } job->len = len; job->flags = flags; job->callback = callback; return job; exit_0: free(job); return NULL; } job_t *job_push(job_queue_t *q, job_t *job) { if (!job || sem_wait(&q->lock) == -1) return NULL; if (!q->next) q->next = job; if (q->last) q->last->next = job; q->last = job; sem_post(&q->jobs); sem_post(&q->lock); return job; } job_t *job_push_new(job_queue_t *q, void *(*f)(void *), void *arg, size_t len, void (*callback)(void *), int flags) { job_t *job = job_new(f, arg, len, callback, flags); if (!job) return NULL; return job_push(q, job); } static void job_free(job_t *job) { if (job->flags & JOB_FREE) free(job->arg); if (job->flags & JOB_RET) free(job->ret); free(job); } static void *job_seek(void *arg) { job_thread_t *jt = (job_thread_t *)arg; job_t *job; while((job = job_wait(jt->q))) { pthread_cleanup_push((void (*)(void *))job_free, job); jt->q->cur = job; if (job->f) job->ret = job->f(job->arg); if (job->callback) job->callback(job->arg); pthread_cleanup_pop(1); /* job_free(job) */ } /* never reached */ return jt; } void job_queue_destroy(job_queue_t *q) { job_t *job; while ((job = job_shift(q))) { job_free(job); } for (size_t z = 0; z < q->nthreads; z++) { pthread_cancel(q->thread[z].thread); } for (size_t z = 0; z < q->nthreads; z++) { pthread_join(q->thread[z].thread, NULL); } sem_destroy(&q->lock); sem_destroy(&q->jobs); sem_destroy(&q->done); free(q->thread); free(q); } #define qthread &q->thread[q->nthreads] job_queue_t *job_queue_create(size_t nthreads) { job_queue_t *q = calloc(1, sizeof (job_queue_t)); if (!q) return NULL; q->thread = calloc(nthreads, sizeof (job_thread_t)); if (!q->thread) goto err_free_q; if (sem_init(&q->done, 0, 0)) goto err_free_qthread; if (sem_init(&q->jobs, 0, 0)) goto err_sem_destroy_done; if (sem_init(&q->lock, 0, 1)) goto err_sem_destroy_jobs; while (q->nthreads < nthreads) { q->thread[q->nthreads].id = q->nthreads; q->thread[q->nthreads].q = q; if (pthread_create(qthread.thread, NULL, &job_seek, qthread)) { goto err_job_queue_destroy; } q->nthreads++; } return q; err_job_queue_destroy: job_queue_destroy(q); return NULL; err_sem_destroy_jobs: sem_destroy(&q->jobs); err_sem_destroy_done: sem_destroy(&q->done); err_free_qthread: free(q->thread); err_free_q: free(q); return NULL; } librecast/libs/libmld/src/job.h000066400000000000000000000044601502456746400167550ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2020-2023 Brett Sheffield */ #ifndef _JOB_H #define _JOB_H 1 #include #include enum job_flag { JOB_COPY = 1, /* copy arg */ JOB_FREE = 2, /* free arg */ JOB_RET = 4, /* free return arg */ JOB_WAIT = 8, /* don't return until job done */ }; typedef struct job_s job_t; typedef struct job_queue_s job_queue_t; typedef struct job_thread_s job_thread_t; struct job_s { void *(*f)(void *arg); /* function for thread to call */ void *arg; /* pass this argument to f() */ void *ret; /* return value from f() */ size_t len; /* size of arg */ job_t *next; /* ptr to next job */ int flags; /* job flags */ void (*callback)(void *); /* callback when done */ }; struct job_queue_s { job_t *next; /* next job */ job_t *last; /* last job */ job_t *cur; /* current job */ size_t nthreads; /* number of threads in pool */ job_thread_t *thread; /* array of threads */ sem_t jobs; /* semaphore of avail jobs */ sem_t lock; /* read/write lock */ /* Optional semaphore - set manually when queue complete */ sem_t done; }; struct job_thread_s { size_t id; pthread_t thread; job_queue_t *q; }; /* Create new job queue with nthreads worker threads */ job_queue_t *job_queue_create(size_t nthreads); /* Free a queue and join its threads */ void job_queue_destroy(job_queue_t *q); /* Create new job. * callback is called with the job as argument. Can be called with &free to free * job when done if nothing else needs to access it */ job_t *job_new(void *(*f)(void *), void *arg, size_t len, void (*callback)(void *), int flags); /* Push a new job onto the end of the queue. */ job_t *job_push(job_queue_t *q, job_t *job); /* create a job and push onto the queue in one call */ job_t *job_push_new(job_queue_t *q, void *(*f)(void *), void *arg, size_t len, void (*callback)(void *), int flags); /* Shift the next job from the front of the queue (FIFO) with no locks. * Use job_trywait() or job_wait() if lock required */ job_t *job_shift(job_queue_t *q); /* Shift a job from the queue with locking. Return immediately if none * available */ job_t *job_trywait(job_queue_t *q); /* Wait for a job. Does not return until one available */ job_t *job_wait(job_queue_t *q); #endif /* _JOB_H */ librecast/libs/libmld/src/log.c000066400000000000000000000022341502456746400167540ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only * Copyright (c) 2012-2022 Brett Sheffield */ #include #include #include #include #include #include #include "log.h" #define LOG_BUFSIZE 256 unsigned int loglevel = LOG_LOGLEVEL_DEFAULT; static int uselock; static sem_t loglock; void loginit(void) { uselock = 1; sem_init(&loglock, 0, 1); } void logwait(void) { if (uselock) sem_wait(&loglock); } void logdone(void) { if (uselock) sem_post(&loglock); } void logmsg(unsigned int level, const char *fmt, ...) { int len; char *mbuf = NULL; char buf[LOG_BUFSIZE]; char *b = buf; va_list argp; if ((level & loglevel) != level) return; va_start(argp, fmt); len = vsnprintf(buf, LOG_BUFSIZE, fmt, argp); if (len >= LOG_BUFSIZE) { /* need a bigger buffer, resort to malloc */ mbuf = malloc(len + 1); va_end(argp); va_start(argp, fmt); vsprintf(mbuf, fmt, argp); b = mbuf; } va_end(argp); if (uselock) logwait(); if (level >= LOG_TRACE) { fprintf(stderr, "%li: ", (long int)clock()); } fprintf(stderr, "%s\n", b); if (uselock) logdone(); free(mbuf); } librecast/libs/libmld/src/log.h000066400000000000000000000046601502456746400167660ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only * Copyright (c) 2012-2023 Brett Sheffield */ #ifndef __LSD_LOG #define __LSD_LOG 1 #define LOG_ENABLE 0 #define DEBUG_ON 0 #define LOG_LEVELS(X) \ X(0, LOG_NONE, "none") \ X(1, LOG_SEVERE, "severe") \ X(2, LOG_ERROR, "error") \ X(4, LOG_WARNING, "warning") \ X(8, LOG_INFO, "info") \ X(16, LOG_TRACE, "trace") \ X(32, LOG_FULLTRACE, "fulltrace") \ X(64, LOG_DEBUG, "debug") #undef X #define LOG_ENUM(id, name, desc) name = id, enum { LOG_LEVELS(LOG_ENUM) }; #define LOG_LOGLEVEL_DEFAULT 15 #define LOG_LOGLEVEL_VERBOSE 79 extern unsigned int loglevel; #if LOG_ENABLE # define LOG(lvl, ...) if ((lvl & loglevel) == lvl) logmsg(lvl, __VA_ARGS__) # define INFO(...) do { LOG(LOG_INFO, __VA_ARGS__); } while(0) # define ERROR(...) do { LOG(LOG_ERROR, __VA_ARGS__); } while(0) # define BREAK(lvl, ...) do {LOG(lvl, __VA_ARGS__); break;} while(0) # define CONTINUE(lvl, ...) do {LOG(lvl, __VA_ARGS__); continue;} while(0) # define DIE(...) do {LOG(LOG_SEVERE, __VA_ARGS__); _exit(EXIT_FAILURE);} while(0) #else # define LOG(...) while(0) # define INFO(...) while(0) # define ERROR(...) while(0) # define BREAK(...) while(0) # define CONTINUE(...) while(0) # define DIE(...) while(0) #endif #if DEBUG_ON # define DEBUG(...) do { if (DEBUG_ON) LOG(LOG_DEBUG, __VA_ARGS__); } while(0) #else # define DEBUG(...) while(0) #endif #define FMTV(iov) (int)(iov).iov_len, (const char *)(iov).iov_base #define ERRMSG(err) {LOG(LOG_ERROR, err_msg(err));} #define FAIL(err) {LOG(LOG_ERROR, err_msg(err)); return err;} #define FAILMSG(err, ...) do {LOG(LOG_ERROR, __VA_ARGS__); return err;} while(0) #define TRACE(...) do {LOG(LOG_TRACE, __VA_ARGS__);} while(0) #define FTRACE(...) do {LOG(LOG_FULLTRACE, __VA_ARGS__);} while(0) #define WARN(...) do {LOG(LOG_WARNING, __VA_ARGS__);} while(0) /* initialize logger & enable locking (optional) */ void loginit(void); /* grab the log semaphore */ void logwait(void); /* release log semaphore */ void logdone(void); /* format log message */ void logmsg(unsigned int level, const char *fmt, ...) #ifdef __GNUC__ __attribute__((format(printf, 2 ,3))) #endif ; #endif /* __LSD_LOG */ librecast/libs/libmld/src/macro.h000066400000000000000000000003071502456746400173000ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2020-2022 Brett Sheffield */ #define aitoin6(ai) &(((struct sockaddr_in6 *)ai->ai_addr)->sin6_addr) librecast/libs/libmld/src/misc.c000066400000000000000000000011271502456746400171260ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2020-2022 Brett Sheffield */ #include #include #include "misc.h" /* Public Domain, credit to Sean Anderson from * https://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2 */ uint32_t next_pow2(uint32_t v) { v--; v |= v >> 1; v |= v >> 2; v |= v >> 4; v |= v >> 8; v |= v >> 16; return ++v; } int _vscprintf (const char * format, va_list argp) { int r; va_list argc; va_copy(argc, argp); r = vsnprintf(NULL, 0, format, argc); va_end(argc); return r; } librecast/libs/libmld/src/misc.h000066400000000000000000000010351502456746400171310ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2020-2022 Brett Sheffield */ #ifndef _LIBRESTACK_MISC_H__ #define _LIBRESTACK_MISC_H__ 1 #include #include #define verify_expr(R, E) \ (_GL_VERIFY_TRUE (R, "verify_expr (" #R ", " #E ")") ? (E) : (E)) /* return next highest power of two */ uint32_t next_pow2(uint32_t v); /* return size of buffer to allocate for vsnprintf() */ int _vscprintf (const char * format, va_list argp); #endif /* _LIBRESTACK_MISC_H__ */ librecast/libs/libmld/src/mld.c000066400000000000000000001107531502456746400167550ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2020-2024 Brett Sheffield */ #define _GNU_SOURCE /* required for struct in6_pktinfo */ #include "config.h" #include "mld_pvt.h" #include "log.h" #ifdef __linux__ # include # include # include # include # include #endif #if HAVE_ASM_TYPES_H # include #endif #if HAVE_SYS_PARAM_H #include #endif #if HAVE_SYS_SOCKET_H # include #endif #if HAVE_SYS_TYPES_H #include #endif #if HAVE_NETINET6_IP6_MROUTE_H # define OS_NETBSD 1 # include #endif #ifdef HAVE_FCNTL_H # include #endif #ifdef HAVE_NET_BPF_H # include # ifndef sock_filter # define sock_filter bpf_insn # define sock_fprog bpf_program # endif #endif #ifdef HAVE_SYS_IOCTL_H # include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_ENDIAN_H # include #elif defined(HAVE_SYS_ENDIAN_H) # include #elif defined(HAVE_LIBKERN_OSBYTEORDER_H) # include # define be64toh(x) OSSwapBigToHostInt64(x) #endif /* BPF filter for MLD types - we are interested in icmpv6 types 130-132 and 143 */ /* tcpdump -dd 'ip6[6] == 0 and * ((ip6[40:4] == 0x3a000502 and ip6[44:2] == 0) or * (ip6[40:4] == 0x3a000100 and ip6[44:4] == 0x05020000)) and * (ip6[48] == 130 or ip6[48] == 131 or ip6[48] == 132 or ip6[48] == 143)' * notes: * ip6[6] == 0: first header is an option header * ip6[40:4] == 0x3a000502: router alert, next header ICMP6 and Option header 0 * ip6[44:2] == 0: alert type MLD * -or- * ip6[40:4] == 0x3a000100: router alert, next header ICMP6 and Option header 1 * ip6[44:4] == 0x05020000: alert type MLD * ip6[48]: ICMP6 type in ICMP6 header */ static struct sock_filter BPF_MLD[] = { { 0x28, 0, 0, 0x0000000c }, { 0x15, 0, 15, 0x000086dd }, { 0x30, 0, 0, 0x00000014 }, { 0x15, 0, 13, 0x00000000 }, { 0x20, 0, 0, 0x00000036 }, { 0x15, 0, 2, 0x3a000502 }, { 0x28, 0, 0, 0x0000003a }, { 0x15, 3, 9, 0x00000000 }, { 0x15, 0, 8, 0x3a000100 }, { 0x20, 0, 0, 0x0000003a }, { 0x15, 0, 6, 0x05020000 }, { 0x30, 0, 0, 0x0000003e }, { 0x15, 3, 0, 0x00000082 }, { 0x15, 2, 0, 0x00000083 }, { 0x15, 1, 0, 0x00000084 }, { 0x15, 0, 1, 0x0000008f }, { 0x6, 0, 0, 0x00040000 }, { 0x6, 0, 0, 0x00000000 }, }; static void mld_query_send(mld_t *mld, unsigned int ifx, struct in6_addr *saddr); static inline void mld_watch_event_push(mld_t *mld, unsigned int ifx, struct in6_addr *addr, int type); void mld_loglevel_set(int level) { loglevel = level; } static void freewatchlist(mld_watch_t *w) { for (mld_watch_t *p = w; w; p = w, w = w->next, free(p)); } static void freegrplist(mld_grp_list_t *g) { for (mld_grp_list_t *p = g; g; p = g, g = g->next, free(p)); } static void freeifacelist(mld_iface_t *i) { for (mld_iface_t *p = i; i; p = i, i = i->next, free(p)) { if (i->grp) freegrplist(i->grp); } } static mld_iface_t *mld_get_iface(const mld_t *mld, const unsigned int ifx) { for (mld_iface_t *i = aload(&mld->iface); i; i = aload(&i->next)) { if (i->ifx == ifx) return i; } return NULL; } mld_grp_list_t *mld_get_grp(const mld_t *mld, const unsigned int ifx, const struct in6_addr *grp) { mld_iface_t *i = mld_get_iface(mld, ifx); if (!i) { errno = ENODEV; return NULL; } for (mld_grp_list_t *g = i->grp; g; g = g->next) { if (!memcmp(&g->addr, grp, sizeof(struct in6_addr))) return g; } return NULL; } void mld_free(mld_t *mld) { int err = errno; freewatchlist(mld->watch); freeifacelist(mld->iface); sem_destroy(&mld->sem_mld); sem_destroy(&mld->sem_state); #if HAVE_NETLINK sem_destroy(&mld->sem_netlink); #endif free(mld); errno = err; } int mld_del_iface(mld_t *mld, unsigned int ifx) { mld_iface_t *i, *p = NULL; for (i = mld->iface; i; i = i->next) { if (i->ifx == ifx) break; p = i; } if (!i) { errno = ENODEV; return -1; } #if OS_NETBSD close(i->bpf); #endif if (p) { p->next = i->next; } else { mld->iface = i->next; } if (i->grp) freegrplist(i->grp); free(i); mld_watch_event_push(mld, ifx, NULL, MLD_EVENT_IFDOWN); return 0; } /* join MLD2_CAPABLE_ROUTERS on interface ifx */ static int mld_join_iface(mld_t *mld, unsigned int ifx) { struct ipv6_mreq req = {0}; struct sockaddr_in6 *llocal; struct ifaddrs *ifaddr = NULL; mld_iface_t *iface = mld_get_iface(mld, ifx); assert(iface); if (inet_pton(AF_INET6, MLD2_CAPABLE_ROUTERS, &(req.ipv6mr_multiaddr)) != 1) { return -1; } req.ipv6mr_interface = ifx; if (getifaddrs(&ifaddr)) { ERROR("%s() getifaddrs: %s\n", __func__, strerror(errno)); return -1; } /* find link-local address for ifx and bind to perform JOIN */ for (struct ifaddrs *ifa = ifaddr; ifa; ifa = ifa->ifa_next) { if (if_nametoindex(ifa->ifa_name) != ifx) { continue; } if (ifa->ifa_addr->sa_family !=AF_INET6) { continue; } llocal = ((struct sockaddr_in6 *)ifa->ifa_addr); if (!IN6_IS_ADDR_LINKLOCAL(&llocal->sin6_addr)) { continue; } if (!(ifa->ifa_flags & IFF_MULTICAST)) { continue; } int sock = aload(&mld->sock); if (!setsockopt(sock, IPPROTO_IPV6, IPV6_JOIN_GROUP, &req, sizeof(req))) { DEBUG("MLD listening on interface %s[%u]\n", ifa->ifa_name, ifx); memcpy(&iface->llink, llocal, sizeof(struct sockaddr_in6)); } else { ERROR("%s() setsockopt: %s\n", __func__, strerror(errno)); } astor(&mld->sock, sock); } freeifaddrs(ifaddr); /* send MLD2 General Queries */ mld_query_send(mld, ifx, NULL); return 0; } #if OS_NETBSD static int mld_bpf_init(char *ifname) { struct sock_fprog prog = { .bf_len = sizeof(BPF_MLD) / sizeof(BPF_MLD[0]), .bf_insns = BPF_MLD, }; struct ifreq ifr = {0,}; int bpf; const int opt = 1; bpf = open("/dev/bpf", O_RDONLY); if (bpf == -1) goto exit_0; strcpy(ifr.ifr_name, ifname); if (ioctl(bpf, BIOCSETIF, &ifr) == -1) goto exit_1; if (ioctl(bpf, BIOCIMMEDIATE, &opt)) goto exit_1; if (ioctl(bpf, BIOCSETF, &prog) == -1) goto exit_1; exit_0: return bpf; exit_1: close(bpf); return bpf; } #endif int mld_add_iface(mld_t *mld, unsigned int ifx, char *ifname) { mld_iface_t *iface; if (strlen(ifname) >= 16) return (errno = ENAMETOOLONG), -1; if (mld_get_iface(mld, ifx)) return (errno = ENODEV), -1; iface = calloc(1, sizeof(mld_iface_t)); if (!iface) return -1; astor(&iface->next, aload(&mld->iface)); iface->ifx = ifx; strcpy(iface->ifname, ifname); #if OS_NETBSD iface->bpf = mld_bpf_init(ifname); #endif astor(&mld->iface, iface); mld_join_iface(mld, ifx); DEBUG("ifx %u added\n", ifx); mld_watch_event_push(mld, ifx, NULL, MLD_EVENT_IFUP); return 0; } int mld_add_iface_ifx(mld_t *mld, unsigned int ifx) { char ifname[IF_NAMESIZE]; if (!if_indextoname(ifx, ifname)) { ERROR("%s() if_indextoname: %s\n", __func__, strerror(errno)); return -1; } return mld_add_iface(mld, ifx, ifname); } void *mld_state_ifx_del(void *arg) { struct mld_txn_s *txn = arg; #if 0 if (!if_indextoname(txn->ifx, ifname)) { ERROR("trying to delete unknown ifx %u", txn->ifx); txn->err = errno; txn->ret = -1; return arg; } #endif txn->ret = mld_del_iface(txn->mld, txn->ifx); txn->err = errno; return arg; } void *mld_state_ifx_add(void *arg) { struct mld_txn_s *txn = arg; char ifname[IF_NAMESIZE]; if (!if_indextoname(txn->ifx, ifname)) { txn->err = errno; txn->ret = -1; return arg; } txn->ret = mld_add_iface(txn->mld, txn->ifx, ifname); txn->err = errno; return arg; } /* create a grp list for each multicast capable interface */ void *mld_state_ifx_add_all(void *arg) { mld_t *mld = (mld_t *)arg; struct ifaddrs *ifa = NULL, *ifap = NULL; unsigned int ifx; if (getifaddrs(&ifa) == -1) { ERROR("%s() getifaddrs(): %s\n", __func__, strerror(errno)); return NULL; } for (ifap = ifa; ifap; ifap = ifap->ifa_next) { if (!(ifap->ifa_flags & IFF_MULTICAST)) continue; if (ifap->ifa_addr == NULL) continue; if (ifap->ifa_addr->sa_family != AF_INET6) continue; ifx = if_nametoindex(ifap->ifa_name); mld_add_iface(mld, ifx, ifap->ifa_name); } freeifaddrs(ifa); return arg; } static int mld_state_grp_del_entry(mld_iface_t *iface, struct in6_addr *addr) { mld_grp_list_t *grp, *p = NULL; for (grp = iface->grp; grp; p = grp, grp = grp->next) { if (!memcmp(&grp->addr, addr, sizeof(struct in6_addr))) break; } if (!grp) { errno = ENOENT; return -1; } if (p) { p->next = grp->next; } else { iface->grp = grp->next; } free(grp); return 0; } static void *mld_state_grp_del(void *arg) { struct mld_txn_s *txn = arg; mld_iface_t *iface = mld_get_iface(txn->mld, txn->ifx); if (!iface) { txn->err = ENODEV; txn->ret = -1; return arg; } txn->ret = mld_state_grp_del_entry(iface, txn->addr); txn->err = errno; return arg; } static int mld_state_grp_check(struct mld_txn_s *txn) { mld_grp_list_t *grp; if ((grp = mld_get_grp(txn->mld, txn->ifx, txn->addr))) { struct timespec ts = {0}; mld_iface_t *iface = mld_get_iface(txn->mld, txn->ifx); if (!iface) return (errno = ENODEV), -1; if (clock_gettime(CLOCK_REALTIME, &ts) == -1) return -1; if (grp->expires.tv_sec <= ts.tv_sec) { /* expired, delete */ return mld_state_grp_del_entry(iface, txn->addr); } else { txn->expires.tv_sec = grp->expires.tv_sec; txn->expires.tv_nsec = grp->expires.tv_nsec; return 1; } } return 0; } static void *mld_state_grp_cmp(void *arg) { struct mld_txn_s *txn = arg; mld_iface_t *iface; if (!txn->ifx) { /* check all interfaces, return 1 if *any* match */ txn->ret = 0; for (mld_iface_t *i = txn->mld->iface; i; i = i->next) { txn->ifx = i->ifx; txn->ret = mld_state_grp_check(txn); if (txn->ret) break; } } else if (!(iface = mld_get_iface(txn->mld, txn->ifx))) { txn->err = ENODEV; txn->ret = -1; } else { txn->ret = mld_state_grp_check(txn); txn->err = errno; } return arg; } static void *mld_state_grp_add(void *arg) { struct mld_txn_s *txn; if (!arg) return NULL; txn = arg; mld_grp_list_t *grp; mld_iface_t *iface = mld_get_iface(txn->mld, txn->ifx); if (!iface) { txn->err = ENODEV; txn->ret = -1; return arg; } grp = mld_get_grp(txn->mld, txn->ifx, txn->addr); if (!grp) { /* not found, add group */ grp = calloc(1, sizeof(mld_grp_list_t)); if (!grp) { txn->ret = -1; return arg; } grp->next = iface->grp; memcpy(&grp->addr, txn->addr, sizeof(struct in6_addr)); iface->grp = grp; } else { txn->ret = 1; } grp->expires.tv_sec = txn->expires.tv_sec; grp->expires.tv_nsec = txn->expires.tv_nsec; #if DEBUG_ON char strgrp[INET6_ADDRSTRLEN]; char ifname[IF_NAMESIZE]; if_indextoname(txn->ifx, ifname); inet_ntop(AF_INET6, &grp->addr, strgrp, INET6_ADDRSTRLEN); //DEBUG("%s(): %s on %s[%u]", __func__, strgrp, ifname, txn->ifx); #endif return arg; } void mld_watch_del(mld_watch_t *watch) { mld_watch_t *next = aload(&watch->next); mld_watch_t *prev = aload(&watch->prev); if (prev) astor(&prev->next, next); else astor(&watch->mld->watch, next); free(watch); } mld_watch_t *mld_watch_add(mld_t *mld, unsigned int ifx, struct in6_addr *addr, void (*f)(mld_watch_t *), void *arg, int flags) { mld_watch_t *watch = malloc(sizeof(mld_watch_t)); if (!watch) return NULL; memset(watch, 0, sizeof(mld_watch_t)); watch->mld = mld; watch->ifx = ifx; watch->arg = arg; watch->flags = flags; watch->f = f; if (addr) memcpy(&watch->grp, addr, sizeof(struct in6_addr)); if (mld->watch) { watch->next = mld->watch; mld->watch->prev = watch; } astor(&mld->watch, watch); return watch; } mld_t *mld_watch_mld(mld_watch_t *watch) { return watch->mld; } unsigned int mld_watch_ifx(mld_watch_t *watch) { return watch->ifx; } struct in6_addr *mld_watch_grp(mld_watch_t *watch) { return &watch->grp; } void *mld_watch_arg(mld_watch_t *watch) { return watch->arg; } pthread_t mld_watch_tid(mld_watch_t *watch) { return watch->tid; } int mld_watch_flags(mld_watch_t *watch) { return watch->flags; } void mld_wait_callback(mld_watch_t *watch) { sem_post(mld_watch_arg(watch)); } void *mld_wait_callback_thread(void *arg) { mld_watch_t *watch; if (!arg) return NULL; watch = (mld_watch_t *)arg; watch->f((mld_watch_t *)arg); free(arg); return NULL; } int mld_wait(mld_t *mld, unsigned int ifx, struct in6_addr *addr, int flags) { sem_t sem_watch; int rc; if ((rc = mld_filter_grp_cmp(mld, ifx, addr)) == -1) return -1; if (rc == 1) return 0; if (flags & MLD_DONTWAIT) { errno = EWOULDBLOCK; return -1; } if (sem_init(&sem_watch, 0, 0)) return -1; if (mld_watch_add(mld, ifx, addr, &mld_wait_callback, &sem_watch, 0)) { rc = sem_wait(&sem_watch); } else rc = -1; sem_destroy(&sem_watch); return rc; } /* check for watchers, run callbacks in detached thread */ static void *mld_watch_event(void *arg) { pthread_attr_t attr; mld_txn_t *txn; mld_watch_t *event; if (!arg) return NULL; if (pthread_attr_init(&attr)) return NULL; if (pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED)) goto err_attr_destroy; txn = (mld_txn_t *)arg; for (mld_watch_t *w = aload(&txn->mld->watch); w; w = aload(&w->next)) { if (w->ifx && txn->ifx && txn->ifx != w->ifx) continue; if (w->grp.s6_addr[0] && txn->addr && memcmp(txn->addr, &w->grp, sizeof(struct in6_addr))) continue; if (!(txn->type & w->flags)) continue; if (!(event = malloc(sizeof(mld_watch_t)))) break; memcpy(event, w, sizeof(mld_watch_t)); event->flags = txn->type; event->ifx = txn->ifx; if (txn->addr) memcpy(&event->grp, txn->addr, sizeof(struct in6_addr)); if (pthread_create(&w->tid, &attr, &mld_wait_callback_thread, event)) free(event); } free(txn->addr); free(txn); err_attr_destroy: pthread_attr_destroy(&attr); return NULL; } /* push watch event */ static inline void mld_watch_event_push(mld_t *mld, unsigned int ifx, struct in6_addr *addr, int type) { struct in6_addr *grp = NULL; mld_txn_t *txn; if (!mld->q[MLD_WATCH]) return; txn = calloc(1, sizeof (mld_txn_t)); if (!txn) return; if (addr) { grp = malloc(sizeof(struct in6_addr)); if (!grp) goto err_free_txn; memcpy(grp, addr, sizeof(struct in6_addr)); } txn->mld = mld; txn->ifx = ifx; txn->addr = grp; txn->type = type; job_push_new(mld->q[MLD_WATCH], &mld_watch_event, txn, sizeof(*txn), NULL, 0); return; err_free_txn: free(txn); } /* check every grp on every interface for expiry */ static void *mld_state_timer_check(void *arg) { mld_t *mld = (mld_t *)arg; struct timespec now = {0}; if (clock_gettime(CLOCK_REALTIME, &now) == -1) return NULL; for (mld_iface_t *i = mld->iface; i; i = i->next) { for (mld_grp_list_t *g = i->grp, *p = NULL; g;) { if (g->expires.tv_sec <= now.tv_sec) { mld_grp_list_t *tmp = g; /* group has expired - delete and notify watchers */ mld_watch_event_push(mld, i->ifx, &g->addr, MLD_EVENT_PART); if (p) { p->next = g->next; } else { i->grp = g->next; } g = g->next; free(tmp); continue; } else if (g->expires.tv_sec - now.tv_sec <= MLD2_QRI / 1000) { /* group is about to expire, send Query */ mld_query_send(mld, i->ifx, &g->addr); } p = g, g = g->next; } } sem_post(&mld->sem_state); /* allow next timer job */ return arg; } static void txn_done(void *arg) { struct mld_txn_s *txn = (struct mld_txn_s *)arg; sem_post(&txn->done); } static int txn_init(struct mld_txn_s *txn, mld_t *mld, unsigned int ifx, struct in6_addr *addr, struct timespec *ts) { if (sem_init(&txn->done, 0, 0)) return -1; txn->mld = mld; txn->ifx = ifx; txn->addr = addr; if (ts) { txn->expires.tv_sec = ts->tv_sec; txn->expires.tv_nsec = ts->tv_nsec; } return 0; } static int txn_wait(struct mld_txn_s *txn) { if (sem_wait(&txn->done) || sem_destroy(&txn->done)) return -1; errno = txn->err; return txn->ret; } int mld_filter_ifx_del(mld_t *mld, unsigned int ifx) { struct mld_txn_s txn = {0}; if (txn_init(&txn, mld, ifx, NULL, NULL) == -1) return -1; if (!job_push_new(mld->q[MLD_STATE], &mld_state_ifx_del, &txn, sizeof(txn), &txn_done, 0)) return -1; return txn_wait(&txn); } int mld_filter_ifx_add(mld_t *mld, unsigned int ifx) { struct mld_txn_s txn = {0}; if (txn_init(&txn, mld, ifx, NULL, NULL) == -1) return -1; if (!job_push_new(mld->q[MLD_STATE], &mld_state_ifx_add, &txn, sizeof(txn), &txn_done, 0)) return -1; return txn_wait(&txn); } int mld_filter_grp_cmp(mld_t *mld, unsigned int ifx, struct in6_addr *addr) { struct mld_txn_s txn = {0}; if (!addr) { errno = EINVAL; return -1; } /* push job to STATE queue */ if (txn_init(&txn, mld, ifx, addr, NULL) == -1) return -1; if (!job_push_new(mld->q[MLD_STATE], &mld_state_grp_cmp, &txn, sizeof(txn), &txn_done, 0)) return -1; return txn_wait(&txn); } int mld_filter_timer_get(mld_t *mld, unsigned int ifx, struct in6_addr *addr, struct timespec *ts) { struct mld_txn_s txn = {0}; if (!addr) { errno = EINVAL; return -1; } /* push job to STATE queue */ if (txn_init(&txn, mld, ifx, addr, ts) == -1) return -1; if (!job_push_new(mld->q[MLD_STATE], &mld_state_grp_cmp, &txn, sizeof(txn), &txn_done, 0)) return -1; txn_wait(&txn); ts->tv_sec = txn.expires.tv_sec; ts->tv_nsec = txn.expires.tv_nsec; return txn.ret; } int mld_filter_grp_del(mld_t *mld, unsigned int ifx, struct in6_addr *addr) { struct mld_txn_s txn = {0}; assert(mld->q[MLD_STATE]); /* mld_start() MUST have been called first */ if (!addr) { errno = EINVAL; return -1; } /* push job to STATE queue */ if (txn_init(&txn, mld, ifx, addr, NULL) == -1) return -1; if (!job_push_new(mld->q[MLD_STATE], &mld_state_grp_del, &txn, sizeof(txn), &txn_done, 0)) return -1; return txn_wait(&txn); } int mld_filter_timer_set(mld_t *mld, unsigned int ifx, struct in6_addr *addr, struct timespec *ts) { struct mld_txn_s txn = {0}; assert(mld->q[MLD_STATE]); /* mld_start() MUST have been called first */ if (!addr) { errno = EINVAL; return -1; } /* push job to STATE queue to update timer */ if (txn_init(&txn, mld, ifx, addr, ts) == -1) return -1; if (!job_push_new(mld->q[MLD_STATE], &mld_state_grp_add, &txn, sizeof(txn), &txn_done, 0)) return -1; return txn_wait(&txn); } int mld_filter_timer_set_s(mld_t *mld, unsigned int ifx, struct in6_addr *addr, int s) { struct timespec ts = {0}; if (clock_gettime(CLOCK_REALTIME, &ts) == -1) return -1; ts.tv_sec += s; return mld_filter_timer_set(mld, ifx, addr, &ts); } int mld_filter_grp_add(mld_t *mld, unsigned int ifx, struct in6_addr *addr) { mld_watch_event_push(mld, ifx, addr, MLD_EVENT_JOIN); return mld_filter_timer_set_s(mld, ifx, addr, MLD_TIMEOUT); } /* return true if we are the active Querier for mif * passing ts as current time is optional, as calling routines often already * have the current time */ static int mld_is_querier(mld_t *mld, unsigned int ifx, struct timespec *ts) { mld_iface_t *iface = mld_get_iface(mld, ifx); struct timespec now; if (!iface) return 0; if (ts) now.tv_sec = ts->tv_sec; else if (clock_gettime(CLOCK_REALTIME, &now) == -1) return -1; return ((aload(&iface->qseen.tv_sec) + MLD2_OTHER_QUERIER_TIMEOUT) > now.tv_sec) ? 0 : 1; } void mld_query_msg_free(mld_msg_t *msg) { if (msg) free(msg->cmsgbuf); } /* set length of msgh->msg_controllen */ static int mld_query_cmsglen(mld_msg_t *msg) { int rc; if ((rc = inet6_opt_init(NULL, 0)) == -1) { ERROR("inet6_opt_init failed\n"); return -1; } msg->extlen = (socklen_t)rc; assert(msg->extlen > 0); if ((rc = inet6_opt_append(NULL, 0, msg->extlen, IP6OPT_ROUTER_ALERT, 2, 2, NULL)) == -1) { ERROR("inet6_opt_append failed\n"); return -1; } msg->extlen = (socklen_t)rc; assert(msg->extlen > 0); if ((rc = inet6_opt_finish(NULL, 0, msg->extlen)) == -1) { ERROR("inet6_opt_finish failed\n"); return -1; } msg->extlen = (socklen_t)rc; msg->msgh.msg_controllen = CMSG_SPACE(msg->extlen); return 0; } int mld_query_msg(mld_t *mld, unsigned int ifx, struct in6_addr *saddr, mld_msg_t *msg) { (void)mld; /* unused */ (void)ifx; /* unused */ void *databufp = NULL, *extbuf; uint16_t racode = 0; uint8_t qrv = (uint8_t)MLD2_ROBUSTNESS; int offset; if (mld_query_cmsglen(msg) == -1) return -1; msg->cmsgbuf = malloc(msg->msgh.msg_controllen); if (!msg->cmsgbuf) return -1; memset(msg->cmsgbuf, 0, msg->msgh.msg_controllen); msg->dst.sin6_family = AF_INET6; msg->qmsg.type = 130; msg->qmsg.mrc = htobe16(MLD2_QRI); assert(MLD2_ROBUSTNESS <= 0xf); /* QRV is lowest 3 bits in network byte order */ msg->qmsg.bits = htons(qrv); msg->qmsg.qqic = MLD2_QI; msg->iov[0].iov_base = &msg->qmsg; msg->iov[0].iov_len = sizeof(mld_query_msg_t); msg->msgh.msg_name = &msg->dst; msg->msgh.msg_namelen = sizeof(struct sockaddr_in6); msg->msgh.msg_iov = msg->iov; msg->msgh.msg_iovlen = 1; msg->msgh.msg_control = msg->cmsgbuf; msg->cmsgh = CMSG_FIRSTHDR(&msg->msgh); msg->cmsgh->cmsg_len = CMSG_LEN(msg->extlen); msg->cmsgh->cmsg_level = IPPROTO_IPV6; msg->cmsgh->cmsg_type = IPV6_HOPOPTS; extbuf = CMSG_DATA(msg->cmsgh); if ((offset = inet6_opt_init(extbuf, msg->extlen)) == -1) { ERROR("inet6_opt_init"); goto err_free_cmsgbuf; } if ((offset = inet6_opt_append(extbuf, msg->extlen, offset, IP6OPT_ROUTER_ALERT, 2, 2, &databufp)) == -1) { ERROR("inet6_opt_append\n"); goto err_free_cmsgbuf; } inet6_opt_set_val(databufp, 0, &racode, sizeof(racode)); if (inet6_opt_finish(extbuf, msg->extlen, offset) == -1) { ERROR("inet6_opt_finish\n"); goto err_free_cmsgbuf; } if (saddr) { /* Multicast Address Specific Query */ memcpy(&msg->qmsg.addr, saddr, sizeof(struct in6_addr)); memcpy(&msg->dst.sin6_addr, saddr, sizeof(struct in6_addr)); } else { /* MLDv2 General Query */ memset(&msg->dst.sin6_addr, 0, sizeof(struct in6_addr)); if (inet_pton(AF_INET6, MLD2_ALL_NODES, &msg->dst.sin6_addr) != 1) { ERROR("inet_pton\n"); goto err_free_cmsgbuf; } memcpy(&msg->qmsg.addr, &msg->dst.sin6_addr, sizeof(struct in6_addr)); } return 0; err_free_cmsgbuf: free(msg->cmsgbuf); return -1; } static void mld_query_send(mld_t *mld, unsigned int ifx, struct in6_addr *saddr) { mld_msg_t msg = {0}; mld_iface_t *iface; struct timespec now = {0}; int sock = aload(&mld->sock); int opt = 1; iface = mld_get_iface(mld, ifx); if (!iface) return; if (saddr) { /* Multicast Address Specific Query - check timer */ if (clock_gettime(CLOCK_REALTIME, &now) == -1) return; /* check if we are the Querier (for General queries we've already done this) */ if (!mld_is_querier(mld, ifx, &now)) return; mld_grp_list_t *g; g = mld_get_grp(mld, ifx, saddr); if (!g) return; if (now.tv_sec - g->qlast.tv_sec < MLD2_QRI / 1000) return; g->qlast.tv_sec = now.tv_sec; } if (mld_query_msg(mld, ifx, saddr, &msg) == -1) return; if ((setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt))) == -1) { ERROR("setsockopt(SO_REUSEADDR)\n"); } #ifdef SO_REUSEPORT if ((setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, &opt, sizeof(opt))) == -1) { ERROR("setsockopt(SO_REUSEPORT)\n"); } #endif #ifdef SO_BINDTODEVICE /* if a previous call had a bind() and ifx is different from what it had * at the time, the next setsockopt(IPV6_MULTICAST_IF) will fail; this * works around it */ opt = 0; if (setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, &opt, sizeof(opt)) == -1) ERROR("setsockopt(SO_BINDTODEVICE)\n"); #endif if (saddr) { /* bind iff Address Specific Query and address is NOT local scope * FreeBSD fails if we bind() when sending to local scope */ if (!IN6_IS_ADDR_MC_LINKLOCAL(saddr)) { if (bind(sock, (struct sockaddr *)&iface->llink, sizeof(struct sockaddr_in6)) == -1) { ERROR("%s: bind: %s\n", __func__, strerror(errno)); goto err_mld_query_msg_free; } } } if (setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_IF, &ifx, sizeof(ifx)) == -1) ERROR("setsockopt\n"); for (int i = 0; i < MLD2_ROBUSTNESS; i++) { if (sendmsg(sock, &msg.msgh, 0) == -1) ERROR("sendmsg\n"); } astor(&mld->sock, sock); err_mld_query_msg_free: mld_query_msg_free(&msg); } int mld_filter_grp_part(mld_t *mld, unsigned int ifx, struct in6_addr *addr) { mld_query_send(mld, ifx, addr); /* set expiry for group to Query Response Interval */ return mld_filter_timer_set_s(mld, ifx, addr, MLD2_QRI / 1000); } /* extract interface number from ancillary control data */ unsigned int interface_index(struct msghdr *msg) { struct cmsghdr *cmsg; struct in6_pktinfo pi = {0}; unsigned int ifx = 0; for (cmsg = CMSG_FIRSTHDR(msg); cmsg; cmsg = CMSG_NXTHDR(msg, cmsg)) { if (cmsg->cmsg_type == IPV6_PKTINFO) { /* may not be aligned, copy */ memcpy(&pi, CMSG_DATA(cmsg), sizeof pi); ifx = pi.ipi6_ifindex; break; } } assert(ifx); return ifx; } static void mld_address_record(mld_t *mld, unsigned int ifx, mld_addr_rec_t *rec) { struct in6_addr grp = rec->addr; #ifdef DEBUG_ON char strgrp[INET6_ADDRSTRLEN] = {0}; char ifname[IF_NAMESIZE] = {0}; if_indextoname(ifx, ifname); inet_ntop(AF_INET6, &grp, strgrp, INET6_ADDRSTRLEN); #endif //DEBUG("%s type=%u\n", __func__, rec->type); /* XXX: we're ignoring SSM here */ switch (rec->type) { case BLOCK_OLD_SOURCES: case MODE_IS_INCLUDE: case CHANGE_TO_INCLUDE_MODE: DEBUG("INCLUDE %s received on %s(%u)\n", strgrp, ifname, ifx); mld_filter_grp_part(mld, ifx, &grp); break; case MODE_IS_EXCLUDE: case CHANGE_TO_EXCLUDE_MODE: DEBUG("EXCLUDE %s received on %s(%u)\n", strgrp, ifname, ifx); mld_filter_grp_add(mld, ifx, &grp); break; } } #ifndef NDEBUG static #endif void mld_query_handler(mld_t *mld, unsigned int ifx, struct ip6_hdr *ip6h) { mld_iface_t *iface; struct in6_addr *src = (struct in6_addr *)((char *)ip6h + offsetof(struct ip6_hdr, ip6_src)); if (!IN6_IS_ADDR_LINKLOCAL(src)) { DEBUG("MLD Query source is not link local - ignoring\n"); return; } // TODO ignore if hop limit != 1 #if DEBUG_ON char straddrgrp[INET6_ADDRSTRLEN] = {0}; char ifname[IF_NAMESIZE] = {0}; inet_ntop(AF_INET6, src, straddrgrp, INET6_ADDRSTRLEN); if_indextoname(ifx, ifname); DEBUG("processing MLD Query from %s on %s(%u)\n", straddrgrp, ifname, ifx); #endif iface = mld_get_iface(mld, ifx); if (!iface) return; /* Querier Election - compare lowest 64 bits in big-endian order lowest wins */ uint64_t srclo64 = *(uint64_t *)&src->s6_addr[8]; uint64_t loclo64 = *(uint64_t *)&iface->llink.sin6_addr.s6_addr[8]; if (be64toh(srclo64) < be64toh(loclo64)) { /* other node is Querier - set timer */ struct timespec now; if (!clock_gettime(CLOCK_REALTIME, &now) && mld_is_querier(mld, ifx, &now) == 1) { char ifname[IF_NAMESIZE]; if_indextoname(ifx, ifname); DEBUG("Querier detected. Entering Non-Querier state on %s(%u)\n", ifname, ifx); } astor(&iface->qseen.tv_sec, now.tv_sec); } } static void mld2_listen_report(mld_t *mld, unsigned int ifx, struct mld_hdr *mldh) { struct icmp6_hdr *icmpv6 = (struct icmp6_hdr *)mldh; uint16_t recs = ntohs(icmpv6->icmp6_data16[1]); mld_addr_rec_t *mrec = (mld_addr_rec_t *)((char *)mldh + offsetof(struct mld_hdr, mld_addr)); DEBUG("processing mld2 listen report with %u records\n", recs); while (recs--) mld_address_record(mld, ifx, mrec++); } static void mld_msg_handler(mld_t *mld, unsigned int ifx, struct ip6_hdr *ip6h, struct mld_hdr *mldh) { struct in6_addr *mld_addr = (struct in6_addr *)((char *)mldh + offsetof(struct mld_hdr, mld_addr)); switch (mldh->mld_type) { case MLD_LISTENER_QUERY: DEBUG("MLD_LISTENER_QUERY received on %u\n", ifx); mld_query_handler(mld, ifx, ip6h); break; case MLD2_LISTENER_REPORT: DEBUG("MLD2_LISTENER_REPORT received on %u\n", ifx); mld2_listen_report(mld, ifx, mldh); break; case MLD_LISTENER_REPORT: DEBUG("MLD_LISTENER_REPORT received on %u\n", ifx); // TODO: set mldv1 compat mode mld_filter_grp_add(mld, ifx, mld_addr); break; case MLD_LISTENER_DONE: DEBUG("MLD_LISTENER_DONE received on %u\n", ifx); // TODO: set mldv1 compat mode mld_filter_grp_part(mld, ifx, mld_addr); break; default: DEBUG("unhandled icmpv6 type %u received on %u\n", mldh->mld_type, ifx); } } #ifdef __linux__ /* on Linux, unlike BSD, we can listen for BPF packets across ALL interfaces on * a single socket. */ static int mld_listen(mld_t *mld) { char buf[32767] = {0}; struct sockaddr_ll sll = {0}; struct sock_fprog bpf = { .len = sizeof(BPF_MLD) / sizeof(BPF_MLD[0]), .filter = BPF_MLD, }; struct mld_hdr *mldh; struct ip6_hdr *ip6h; struct iovec iov[3] = {0}; struct msghdr msg = {0}; char ethh[14] = {0}; char ipv6[48] = {0}; ssize_t byt; unsigned int ifx; int rc = -1, sock; sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); if (sock == -1) return -1; if (setsockopt(sock, SOL_SOCKET, SO_ATTACH_FILTER, &bpf, sizeof(bpf)) == -1) { ERROR("setsockopt(SO_ATTACH_FILTER)\n"); goto err_close_sock; } astor(&mld->listen_sock, sock); /* prepare scatter/gather structs */ iov[0].iov_base = ðh; iov[0].iov_len = sizeof ethh; iov[1].iov_base = ipv6; iov[1].iov_len = sizeof ipv6; iov[2].iov_base = buf; iov[2].iov_len = sizeof buf; msg.msg_name = &sll; msg.msg_namelen = sizeof sll; msg.msg_iov = iov; msg.msg_iovlen = sizeof iov / sizeof iov[0]; msg.msg_flags = 0; while (1) { sock = aload(&mld->listen_sock); byt = recvmsg(sock, &msg, 0); if (byt == -1) { ERROR("read/recvmsg"); goto err_close_sock; } mldh = (struct mld_hdr *)(buf); ip6h = (struct ip6_hdr *)&ipv6; ifx = (unsigned int)sll.sll_ifindex; DEBUG("received type %u on %u (%zi bytes)\n", mldh->mld_icmp6_hdr.icmp6_type, ifx, byt); if (ifx) mld_msg_handler(mld, ifx, ip6h, mldh); } err_close_sock: close(sock); return rc; } #endif #ifndef __linux__ /* return interface id matching BPF file descriptor */ static inline unsigned int bpffd2ifx(mld_t *mld, int bpffd) { for (mld_iface_t *iface = mld->iface; iface; iface = iface->next) { if (iface->bpf == bpffd) return iface->ifx; } return 0; } /* on BSD, we poll() and read() an array of /dev/bpf filehandles (one per NIC) * BPF filehandles MUST be bound to a single NIC with BIOCSETIF */ static int mld_listen(mld_t *mld) { struct pollfd *fds; struct mld_hdr *mldh; struct ip6_hdr *ip6h; struct bpf_hdr *bpfh; char straddr[INET6_ADDRSTRLEN] = ""; char *buf; ssize_t byt; unsigned int blen = 32767; unsigned int ifx; int err = 0, nfds = 0, rc = 0; for (mld_iface_t *iface = mld->iface; iface; iface = iface->next) nfds++; if (!nfds) return -1; /* create a buffer of correct size for BPF */ if (ioctl(mld->iface->bpf, BIOCGBLEN, &blen) == -1) return -1; buf = malloc((size_t)blen); if (!buf) return -1; memset(buf, 0, (size_t)blen); /* create array of pollfd structures */ fds = calloc(nfds, sizeof (struct pollfd)); if (!fds) { err = errno; rc = -1; goto err_free_buf; } mld_iface_t *iface = mld->iface; for (int i = 0; i < nfds; i++) { fds[i].fd = iface->bpf; fds[i].events = POLLIN; iface = iface->next; } while (nfds > 0) { rc = poll(fds, (nfds_t) nfds, 1000); pthread_testcancel(); if (rc > 0) { for (int i = 0; i < nfds; i++) { if (fds[i].revents & POLLIN) { byt = read(fds[i].fd, buf, (size_t)blen); if (byt > 0) { bpfh = (struct bpf_hdr *)buf; ip6h = (struct ip6_hdr *)(buf + bpfh->bh_hdrlen + 14); mldh = (struct mld_hdr *)(buf + bpfh->bh_hdrlen + 62); inet_ntop(AF_INET6, &(mldh->mld_addr), straddr, sizeof straddr); DEBUG("%u: %s(%zi bytes)", mldh->mld_icmp6_hdr.icmp6_type, straddr, byt); ifx = bpffd2ifx(mld, fds[i].fd); if (ifx) mld_msg_handler(mld, ifx, ip6h, mldh); } } else if (fds[i].revents & (POLLHUP | POLLERR)) { /* socket closed or other error, stop checking it */ nfds--; if (i != nfds) fds[i] = fds[nfds]; i--; } } } if (rc < 0 && errno != EINTR) { err = errno; break; } } free(fds); if (nfds == 0 && err == 0) { err = EIO; rc = -1; } err_free_buf: free(buf); if (err) errno = err; return rc; } #endif static void *mld_thread_listen(void *arg) { mld_t *mld = (mld_t *)arg; /* release semaphore - we're good to go */ if (sem_post(&mld->sem_mld) == -1) goto err_close_sock; /* wait until state thread is ready */ if (sem_wait(&mld->sem_state) == -1) goto err_close_sock; mld_listen(mld); return NULL; err_close_sock: close(mld->sock); return NULL; } #if HAVE_NETLINK static void mld_handle_netlink_msg(mld_t *mld, struct nlmsghdr *msg) { struct ifinfomsg *ifi = NLMSG_DATA(msg); switch (msg->nlmsg_type) { case RTM_NEWLINK: if (ifi->ifi_flags & IFF_UP) { mld_filter_ifx_add(mld, ifi->ifi_index); } else { mld_filter_ifx_del(mld, ifi->ifi_index); } break; case RTM_DELLINK: DEBUG("RTM_DELLINK\n"); mld_filter_ifx_del(mld, ifi->ifi_index); break; default: DEBUG("unknown netlink event type: %i\n", msg->nlmsg_type); break; } } static void *mld_thread_netlink(void *arg) { mld_t *mld = (mld_t *)arg; /* 8192 to avoid message truncation on platforms with page size > 4096 */ struct nlmsghdr buf[8192/sizeof(struct nlmsghdr)]; struct iovec iov = { buf, sizeof(buf) }; struct nlmsghdr *nh; struct sockaddr_nl sa; struct msghdr msg = { &sa, sizeof(sa), &iov, 1, NULL, 0, 0 }; ssize_t len; int fd; memset(&sa, 0, sizeof(sa)); sa.nl_family = AF_NETLINK; sa.nl_groups = RTMGRP_LINK; if ((fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) == -1) return NULL; if (bind(fd, (struct sockaddr *) &sa, sizeof(sa)) == -1) { close(fd); return NULL; } sem_post(&mld->sem_netlink); while (1) { len = recvmsg(fd, &msg, 0); if (len == -1) continue; for (nh = (struct nlmsghdr *)buf; NLMSG_OK(nh, (size_t)len); nh = NLMSG_NEXT(nh, len)) { /* The end of multipart message */ if (nh->nlmsg_type == NLMSG_DONE) continue; if (nh->nlmsg_type == NLMSG_ERROR) ERROR("NLMSG_ERROR\n"); else mld_handle_netlink_msg(mld, nh); } } return arg; } #endif static void *mld_thread_timer(void *arg) { mld_t *mld = (mld_t *)arg; while (1) { sleep(1); /* we use a semaphore to ensure we only queue a maximum of one * job at a time, even when STATE thread is busy */ if (sem_trywait(&mld->sem_state) == -1) continue; job_push_new(mld->q[MLD_STATE], &mld_state_timer_check, mld, sizeof(*mld), NULL, 0); } return arg; } mld_t *mld_init(int flags) { (void)flags; /* TODO implement flags */ mld_t *mld; int err = 0; if (!(mld = malloc(sizeof(mld_t)))) return NULL; memset(mld, 0, sizeof(mld_t)); if (sem_init(&mld->sem_mld, 0, 0) == -1) { err = errno; goto err_free_mld; } if (sem_init(&mld->sem_state, 0, 0) == -1) { err = errno; goto err_sem_mld_destroy; } #if HAVE_NETLINK if (sem_init(&mld->sem_netlink, 0, 0) == -1) { err = errno; goto err_sem_state_destroy; } #endif mld->listen_sock = -1; return mld; #if HAVE_NETLINK err_sem_state_destroy: sem_destroy(&mld->sem_state); #endif err_sem_mld_destroy: sem_destroy(&mld->sem_mld); err_free_mld: free(mld); if (err) errno = err; return NULL; } void mld_stop(mld_t *mld) { for (int i = 0; i < MLD_THREADS; i++) if (mld->q[i]) job_queue_destroy(mld->q[i]); #ifdef __linux__ int sock = aload(&mld->listen_sock); if (sock >= 0) { close(sock); astor(&mld->listen_sock, -1); } #else for (mld_iface_t *iface = mld->iface; iface; iface = iface->next) { if (iface->bpf >= 0) { close(iface->bpf); iface->bpf = -1; } } #endif } mld_t *mld_start(mld_t *mld) { struct timespec ts; const int opt = 1; int err = 0; if (!mld) mld = mld_init(0); if (!mld) return NULL; for (int i = 0; i < MLD_THREADS; i++) { mld->q[i] = job_queue_create(1); if (!mld->q[i]) goto err_mld_stop; } #if HAVE_NETLINK mld->job[MLD_NETLINK] = job_push_new(mld->q[MLD_NETLINK], &mld_thread_netlink, mld, sizeof(*mld), NULL, 0); if (!mld->job[MLD_NETLINK]) goto err_mld_stop; if (sem_wait(&mld->sem_netlink)) goto err_mld_stop; /* make sure netlink is ready */ #endif /* start listen thread and wait for it to initialize */ int sock = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6); if (mld->sock == -1) goto err_mld_stop; if (setsockopt(sock, IPPROTO_IPV6, IPV6_RECVPKTINFO, &opt, sizeof(opt))) goto err_mld_stop; astor(&mld->sock, sock); mld->job[MLD_LISTEN] = job_push_new(mld->q[MLD_LISTEN], &mld_thread_listen, mld, sizeof(*mld), NULL, 0); if (!mld->job[MLD_LISTEN]) goto err_mld_stop; if (clock_gettime(CLOCK_REALTIME, &ts) == -1) goto err_mld_stop; ts.tv_nsec += MLD_LISTEN_THREAD_STARTUP; if (ts.tv_nsec > 999999999L) { ts.tv_nsec -= 1000000000L; ts.tv_sec++; } if (sem_timedwait(&mld->sem_mld, &ts) == -1) goto err_mld_stop; /* push existing interfaces to STATE thread */ mld_state_ifx_add_all(mld); /* let mld_thread_listen() proceed */ if (sem_post(&mld->sem_state) == -1) goto err_mld_stop; /* first mld_thread_timer() run */ if (sem_post(&mld->sem_state) == -1) goto err_mld_stop; /* start timer thread */ if (job_push_new(mld->q[MLD_TIMER], &mld_thread_timer, mld, sizeof(*mld), NULL, 0)) return mld; err_mld_stop: err = errno; mld_stop(mld); errno = err; return NULL; } librecast/libs/libmld/src/mld_pvt.h000066400000000000000000000133051502456746400176460ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2020-2023 Brett Sheffield */ #ifndef MLD_PVT_H #define MLD_PVT_H 1 #include "config.h" #include #include "job.h" #include #ifdef USE_BLOOM_FILTER # include "vec.h" #endif #define MLD_DEBUG 1 #define BUFSIZE 1500 #define IFACE_MAX UCHAR_MAX #ifndef MAXMIFS # define MAXMIFS 32 #endif #ifndef MLD_LISTENER_DONE #define MLD_LISTENER_DONE MLD_LISTENER_REDUCTION #endif /* number of nanoseconds to wait for MLD Listen Thread to initialize */ #define MLD_LISTEN_THREAD_STARTUP 100000000L #define HAVE_NETLINK __linux__ #ifndef aload # define aload(x) __atomic_load_n((x), __ATOMIC_ACQUIRE) #endif #ifndef astor # define astor(x, y) __atomic_store_n((x),(y), __ATOMIC_RELEASE) #endif #ifndef aadd # define aadd(x, y) __atomic_fetch_add((x),(y), __ATOMIC_ACQ_REL) #endif typedef enum { MLD_NETLINK, MLD_LISTEN, MLD_STATE, MLD_TIMER, MLD_WATCH, MLD_THREADS } mld_thread_t; typedef enum { FILTER_MODE_INCLUDE = 1, FILTER_MODE_EXCLUDE, } mld_mode_t; struct mld_iface_s { mld_iface_t *next; mld_grp_list_t *grp; /* link-local address for this interface */ struct sockaddr_in6 llink; /* Last time we saw a Querier that outranked us on this interface. * we set this when we receive an MLD Query with a lower IPv6 address * than us */ struct timespec qseen; /* Last time we sent a Query on this interface */ struct timespec qtime; /* socket to use for outbound PIM JOINs and MLD Queries */ int sock; /* file descriptor for BPF */ int bpf; /* startup query count */ char qcount; char ifname[IF_NAMESIZE]; unsigned int ifx; }; #ifdef USE_BLOOM_FILTER struct mld_timerjob_s { mld_t *mld; void (*f)(mld_t *, unsigned int, size_t, uint8_t); size_t idx; unsigned int iface; uint8_t val; }; struct mld_filter_s { /* counted bloom filter for multicast group addresses */ vec_t grp[BLOOM_VECTORS]; /* bloom timer with 8 bit timer values */ vec_t t[BLOOM_VECTORS]; }; #else struct mld_grp_list_s { mld_grp_list_t *next; struct in6_addr addr; /* Multicast Address */ struct timespec expires; /* record expires */ struct timespec qlast; /* Last MLD Specific Query sent to this group + iface */ }; #endif // IPv6MulticastListen ( socket, interface, IPv6 multicast address, filter mode, source list ) // per-socket state // (interface, IPv6 multicast address, filter mode, source list) // // per-interface state // (IPv6 multicast address, filter mode, source list) typedef enum { MLD_TXN_NOOP, MLD_TXN_CMP, MLD_TXN_ADD, MLD_TXN_REFRESH, MLD_TXN_DEL } mld_txn_type; /* a change in state */ struct mld_txn_s { mld_t *mld; sem_t done; struct in6_addr *addr; /* Multicast Address */ struct timespec expires; /* record expires */ unsigned int ifx; int type; int err; int ret; }; struct mld_watch_s { mld_watch_t *next; mld_watch_t *prev; mld_t *mld; pthread_t tid; void (*f)(mld_watch_t *); void *arg; struct in6_addr grp; unsigned int ifx; int flags; }; struct mld_s { /* stop if cont points to zero value */ volatile int *cont; job_queue_t *q[MLD_THREADS]; job_t *job[2]; /* MLD_NETLINK + MLD_LISTEN threads */ /* raw socket for MLD snooping */ int sock; /* listening socket for the listen thread, to be able to stop receiving */ int listen_sock; /* number of interfaces allocated */ int len; /* interface and address for which we log join/part events */ unsigned int log_ifnumber; const struct sockaddr_in6 *log_addr; sem_t sem_mld; /* MLD listerner thread is ready */ sem_t sem_state; /* state thread is ready */ #if HAVE_NETLINK sem_t sem_netlink; /* netlink thread is ready */ #endif #ifdef USE_BLOOM_FILTER /* counted bloom filter for groups gives us O(1) for insert/query/delete * combined with a bloom timer (is that a thing, or did I just make it * up?) - basically a counted bloom filter where the max is set to the * time in seconds, and we count it down using SIMD instructions */ /* array of filters */ mld_filter_t filter[1]; // FIXME - use linked-list as interfaces can change #else mld_iface_t *iface; #endif mld_watch_t *watch; }; /* Multicast Address Record */ struct mld_addr_rec_s { uint8_t type; /* Record Type */ uint8_t auxl; /* Aux Data Len */ uint16_t srcs; /* Number of Sources */ struct in6_addr addr; /* Multicast Address */ struct in6_addr src[]; /* Source Address */ }; #ifdef static_assert static_assert(sizeof(struct mld_addr_rec_s) == 20, "ensure struct doesn't need packing"); #endif /* Multicast Listener Query Message */ struct mld_query_msg_s { uint8_t type; /* type = 130 */ uint8_t code; uint16_t checksum; uint16_t mrc; /* Maximum Response Code */ uint16_t res1; /* Reserved */ struct in6_addr addr; /* Multicast Address */ uint8_t bits; /* bits: res2[4] supp[1] qrv[3] */ uint8_t qqic; /* Querier's Query Interval Code */ uint16_t srcs; /* Number of Sources */ }; struct mld_msg_s { struct msghdr msgh; struct cmsghdr *cmsgh; struct iovec iov[1]; struct sockaddr_in6 dst; char *cmsgbuf; mld_query_msg_t qmsg; socklen_t extlen; }; /* add interface to mld */ int mld_add_iface(mld_t *mld, unsigned int ifx, char *ifname); /* delete interface from mld */ int mld_del_iface(mld_t *mld, unsigned int ifx); /* PART grp (set timer, send MLD Query if applicable) */ int mld_filter_grp_part(mld_t *mld, unsigned int ifx, struct in6_addr *addr); mld_grp_list_t *mld_get_grp(const mld_t *mld, const unsigned int ifx, const struct in6_addr *grp); unsigned int interface_index(struct msghdr *msg); int mld_query_msg(mld_t *mld, unsigned int ifx, struct in6_addr *saddr, mld_msg_t *msg); void mld_query_msg_free(mld_msg_t *msg); #endif /* MLD_PVT_H */ librecast/libs/libmld/src/vec.c000066400000000000000000000011071502456746400167460ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2020-2022 Brett Sheffield */ #include "vec.h" /* set one element of a vector to value */ void vec_inc_epi8(vec_t *v, size_t idx) { v[idx / VECTOR_BITS].u8[idx % VECTOR_BITS]++; } void vec_dec_epi8(vec_t *v, size_t idx) { (v[idx / VECTOR_BITS].u8[idx % VECTOR_BITS])--; } uint8_t vec_get_epi8(vec_t *v, size_t idx) { return v[idx / VECTOR_BITS].u8[idx % VECTOR_BITS]; } void vec_set_epi8(vec_t *v, size_t idx, uint8_t val) { v[idx / VECTOR_BITS].u8[idx % VECTOR_BITS] = val; } librecast/libs/libmld/src/vec.h000066400000000000000000000011501502456746400167510ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2020-2022 Brett Sheffield */ #ifndef _VEC_H #define _VEC_H 1 #include #include #include #define VECTOR_SZ 16 #define VECTOR_BITS VECTOR_SZ * CHAR_BIT typedef unsigned char u8x16 __attribute__ ((vector_size (VECTOR_SZ))); typedef union { __m128i v; u8x16 u8; } vec_t; void vec_inc_epi8(vec_t *v, size_t idx); void vec_dec_epi8(vec_t *v, size_t idx); uint8_t vec_get_epi8(vec_t *v, size_t idx); void vec_set_epi8(vec_t *v, size_t idx, uint8_t val); #endif /* _VEC_H */ librecast/libs/libmld/test/000077500000000000000000000000001502456746400162165ustar00rootroot00000000000000librecast/libs/libmld/test/.gitignore000066400000000000000000000001041502456746400202010ustar00rootroot00000000000000*.test *.log *.valgrind ????-????.tmp.?????? testlog-?????? lastlog librecast/libs/libmld/test/0000-0000.c000066400000000000000000000005201502456746400173130ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2022 Brett Sheffield */ #include "testnet.h" #include int main(void) { mld_t *mld; test_name("mld_init() / mld_free()"); mld = mld_init(0); test_assert(mld != NULL, "mld_t allocated"); mld_free(mld); return test_status; } librecast/libs/libmld/test/0000-0001.c000066400000000000000000000011351502456746400173170ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2022 Brett Sheffield */ #include "testnet.h" #include int main(void) { mld_t *mld; test_cap_require(CAP_NET_RAW); test_name("mld_start() / mld_stop()"); mld = mld_start(NULL); test_assert(mld != NULL, "mld_t allocated"); if (!mld) return test_status; /* ensure threads started */ for (int i = 0; i < MLD_THREADS; i++) { test_assert(mld->q[i] != NULL, "thread %i started", i); } test_assert(mld != NULL, "mld_t allocated"); mld_stop(mld); mld_free(mld); return test_status; } librecast/libs/libmld/test/0000-0002.c000066400000000000000000000076601502456746400173310ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2022 Brett Sheffield */ #include "testnet.h" #ifdef HAVE_LIBLIBRECAST #include #endif #include #include #include #include #include #include #include int main(void) { char name[] = "mld_filter_grp_cmp() / mld_filter_grp_add()"; #ifdef HAVE_LIBLIBRECAST mld_t *mld; struct in6_addr *addr; struct timespec ts = {0}; lc_ctx_t *lctx; lc_channel_t *chan; unsigned int ifx, ifx_invalid; int rc; test_cap_require(CAP_NET_RAW); test_name(name); test_require_net(TEST_NET_BASIC); ifx = get_multicast_if(); test_assert(ifx, "get_multicast_if() - find multicast capable interface"); if (!ifx) return TEST_WARN; mld = mld_init(0); test_assert(mld != NULL, "mld_t allocated"); if (!mld_start(mld)) { test_assert(0, "mld start failed"); goto err_mld_free; } /* ensure all threads created */ for (int i = 0; i < MLD_THREADS; i++) { assert(mld->q[i]); } ifx_invalid = get_invalid_ifx(); test_assert(ifx_invalid, "get_invalid_ifx() - find invalid interface"); errno = 0; rc = mld_filter_grp_cmp(mld, 0, NULL); test_assert(errno == EINVAL, "mld_filter_grp_cmp() - pass in NULL (EINVAL)"); test_assert(rc == -1, "mld_filter_grp_cmp() - pass in NULL (return -1 error)"); errno = 0; rc = mld_filter_grp_add(mld, ifx, NULL); test_assert(errno == EINVAL, "mld_filter_grp_add() - pass in NULL (EINVAL)"); test_assert(rc == -1, "mld_filter_grp_add() - pass in NULL (return -1 error)"); /* generate a random multicast address */ lctx = lc_ctx_new(); test_assert(lctx != NULL, "lc_ctx_new()"); chan = lc_channel_random(lctx); test_assert(chan != NULL, "lc_channel_random()"); addr = lc_channel_in6addr(chan); test_assert(addr != NULL, "lc_channel_in6addr()"); /* test addr on interface that doesn't exist */ errno = 0; rc = mld_filter_grp_add(mld, ifx_invalid, addr); test_assert(errno == ENODEV, "mld_filter_grp_add() - invalid ifx (ENODEV)"); test_assert(rc == -1, "attempt to add to invalid ifx[%u]", ifx_invalid); /* add grp */ rc = mld_filter_grp_cmp(mld, ifx, addr); test_assert(rc == 0, "check for address before adding to interface[%u] filter", ifx); rc = mld_filter_grp_add(mld, ifx, addr); test_assert(rc == 0, "mld_filter_grp_add() - add address to interface[%u] filter", ifx); rc = mld_filter_grp_cmp(mld, ifx, addr); test_assert(rc == 1, "check address was added to interface[%u] filter", ifx); rc = mld_filter_grp_add(mld, ifx, addr); test_assert(rc == 1, "mld_filter_grp_add() - try to add duplicate address to filter "); /* test with ifx = 0 - MUST find grp regardless of interface */ rc = mld_filter_grp_cmp(mld, 0, addr); test_assert(rc == 1, "check mld_filter_grp_cmp() returns 1 with ifx=0", ifx); /* delete grp */ rc = mld_filter_grp_del(mld, ifx, addr); test_assert(rc == 0, "mld_filter_grp_del() - delete grp from filter"); rc = mld_filter_grp_cmp(mld, ifx, addr); test_assert(rc == 0, "check for address after deleting from filter"); /* add again, check timers */ rc = mld_filter_grp_add(mld, ifx, addr); test_assert(rc == 0, "mld_filter_grp_add() - add address to interface[%u] filter", ifx); rc = mld_filter_grp_cmp(mld, ifx, addr); test_assert(rc == 1, "check address was added to interface[%u] filter", ifx); rc = mld_filter_timer_get(mld, ifx, addr, &ts); test_assert(rc == 1, "ensure timer set"); test_assert(ts.tv_sec > 0, "ensure timer set"); mld_filter_timer_set_s(mld, ifx, addr, 1); /* lower timeout to 1s */ ts.tv_sec = 1; ts.tv_nsec = 100000000; nanosleep(&ts, NULL); /* sleep 1.1s */ rc = mld_filter_grp_cmp(mld, ifx, addr); test_assert(rc == 0, "ensure address expired"); test_assert(mld_get_grp(mld, ifx, addr) == NULL, "ensure grp deleted after expiry"); lc_ctx_free(lctx); mld_stop(mld); err_mld_free: mld_free(mld); return test_status; #else return test_skip("%s - requires liblibrecast", name); #endif } librecast/libs/libmld/test/0000-0003.c000066400000000000000000000031071502456746400173220ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2022-2025 Brett Sheffield */ #include "testnet.h" #include #include #include #include #include #include int main(void) { mld_t *mld; char ifname[IF_NAMESIZE]; unsigned int ifx; int interfaces = 0; int rc; test_name("mld_add_iface() / mld_del_iface()"); test_require_net(TEST_NET_BASIC); ifx = get_multicast_if(); test_assert(ifx, "get_multicast_if() - find multicast capable interface"); if (!ifx) return TEST_WARN; mld = mld_init(0); test_assert(mld != NULL, "mld_init() returned %p", (void *)mld); if (!mld) return test_status; if_indextoname(ifx, ifname); rc = mld_add_iface(mld, ifx, ifname); test_assert(rc == 0, "interface added, return 0: %s", strerror(errno)); rc = mld_add_iface(mld, ifx, ifname); test_assert(rc == -1, "interface exists, return -1"); for (mld_iface_t *i = mld->iface; i; i = i->next) { if (!strcmp(i->ifname, ifname)) interfaces++; } test_assert(interfaces == 1, "mld_add_iface(): ensure duplicate interfaces not added"); rc = mld_del_iface(mld, ifx); test_assert(rc == 0, "interface deleted, return 0: %s", strerror(errno)); interfaces = 0; for (mld_iface_t *i = mld->iface; i; i = i->next) { if (!strcmp(i->ifname, ifname)) interfaces++; } test_assert(interfaces == 0, "mld_del_iface(): ensure interfaces deleted"); rc = mld_del_iface(mld, ifx); test_assert(rc == -1, "try to delete interface that is already deleted, return -1"); mld_free(mld); return test_status; } librecast/libs/libmld/test/0000-0004.c000066400000000000000000000052271502456746400173300ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2022-2025 Brett Sheffield */ #include "testnet.h" #ifdef HAVE_LIBLIBRECAST #include #include #endif #include #include #include #include #include #include int main(void) { char name[] = "netlink thread"; #ifdef HAVE_LIBLIBRECAST mld_t *mld; lc_ctx_t *lctx; lc_channel_t *chan; struct in6_addr *addr; char ifname[IFNAMSIZ] = {0}; unsigned int ifx; int rc, fd; test_require_linux(); test_cap_require(CAP_NET_RAW); test_name(name); test_require_net(TEST_NET_BASIC); mld = mld_init(0); test_assert(mld != NULL, "mld_t allocated"); mld_start(mld); /* ensure all threads created */ for (int i = 0; i < MLD_THREADS; i++) assert(mld->q[i]); /* create an interface */ fd = lc_tap_create(ifname); test_assert(fd > 0, "lc_tap_create()"); ifx = if_nametoindex(ifname); test_assert(ifx > 0, "find ifx for tap"); /* generate a random multicast address */ lctx = lc_ctx_new(); test_assert(lctx != NULL, "lc_ctx_new()"); chan = lc_channel_random(lctx); test_assert(chan != NULL, "lc_channel_random()"); addr = lc_channel_in6addr(chan); test_assert(addr != NULL, "lc_channel_in6addr()"); /* try to find grp on interface before bringing it up */ errno = 0; rc = mld_filter_grp_cmp(mld, ifx, addr); test_assert(errno == ENODEV, "ENODEV before bringing interface up"); test_assert(rc == -1, "try to find grp on interface before bringing it up, -1"); /* bring up interface and check netlink thread has added it */ rc = lc_link_set(lctx, ifname, 1); test_assert(rc == 0, "bring up interface"); usleep(10000); rc = mld_filter_grp_cmp(mld, ifx, addr); test_assert(rc == 0, "try to find grp on interface after bringing it up, 0 (%i)", rc); rc = lc_link_set(lctx, ifname, 1); test_assert(rc == 0, "bring down interface"); usleep(1000); rc = mld_filter_grp_cmp(mld, ifx, addr); // FIXME test_assert(rc == -1, "try to find grp on interface after bringing it down, -1 (%i)", rc); close(fd); /* create another interface, and check netlink thread has added it */ fd = lc_tap_create(ifname); test_assert(fd > 0, "lc_tap_create()"); ifx = if_nametoindex(ifname); test_assert(ifx > 0, "find ifx for tap"); rc = lc_link_set(lctx, ifname, 1); test_assert(rc == 0, "bring up interface"); close(fd); usleep(1000); rc = mld_filter_grp_cmp(mld, ifx, addr); // FIXME test_assert(rc == -1, "try to find grp on interface after deleting, -1"); lc_ctx_free(lctx); mld_stop(mld); mld_free(mld); return test_status; #else return test_skip("%s - requires liblibrecast", name); #endif } librecast/libs/libmld/test/0000-0005.c000066400000000000000000000257411502456746400173340ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2023-2025 Brett Sheffield */ /* test 0000-0005 * * Aim: * ensure MLD Queries are sent when they're supposed to be * * Method: * * - find multicast-capable interface * - mld_init() * - start query thread, listening for MLD Queries on socket * - wait for query thread to release semaphore * - mld_start() * - ensure MLD2 General Queries sent on startup * - create random multicast group (g1) * - ensure g1 not in MLD filter for interface before join * - JOIN g1 * - ensure g1 *is* in filter after join * - PART g1 * - ensure g1 is still in filter after PART * - ensure MLD Query Address Specific Query received * - ensure filter expiry timer set to QRI * - PART g1 again * - ensure no futher Queries sent * - (set QRI timer to simulate another Querier on interface) * - (another Querier present - ensure no MLD Queries received) * - cancel query thread, clean up */ #define _GNU_SOURCE /* required for struct in6_pktinfo */ #include "testnet.h" #ifdef HAVE_LIBLIBRECAST #include #include #endif #include #include #include #include #include #include #include #include #include #ifdef __linux__ #include #include #endif #ifdef HAVE_NET_BPF_H #include #include #define sock_filter bpf_insn #define sock_fprog bpf_program #endif #include #include #include #ifdef HAVE_LIBLIBRECAST static sem_t sem_query; static struct in6_addr *addr; static struct in6_addr allnodes; static volatile int q_gen; static volatile int q_add; /* Thread to count MLD Query packets. * Use a BPF filter on a raw socket so we only receive icmp6 type 130. */ void *thread_query(void *arg) { #ifdef __linux__ (void)arg; /* unused */ struct iovec iov[3] = {0}; struct msghdr msg = {0}; #endif #ifdef HAVE_NET_BPF_H unsigned int ifx = *(unsigned int *)arg; struct ifreq ifr; #endif struct icmp6_hdr *icmpv6; struct mld_hdr mldh = {0}; char *buf = NULL; ssize_t byt; int raw = -1; /* BPF filter: `tcpdump -dd "ip6[48] == 130"` */ /* tcpdump -dd 'ip6[6] == 0 and ((ip6[40:4] == 0x3a000502 and ip6[44:2] * == 0) or (ip6[40:4] == 0x3a000100 and ip6[44:4] == 0x05020000)) and * ip6[48] == 130' */ struct sock_filter code[] = { { 0x28, 0, 0, 0x0000000c }, { 0x15, 0, 13, 0x000086dd }, { 0x30, 0, 0, 0x00000014 }, { 0x15, 0, 11, 0x00000000 }, { 0x20, 0, 0, 0x00000036 }, { 0x15, 0, 2, 0x3a000502 }, { 0x28, 0, 0, 0x0000003a }, { 0x15, 4, 0, 0x00000000 }, { 0x20, 0, 0, 0x00000036 }, { 0x15, 0, 5, 0x3a000100 }, { 0x20, 0, 0, 0x0000003a }, { 0x15, 0, 3, 0x05020000 }, { 0x30, 0, 0, 0x0000003e }, { 0x15, 0, 1, 0x00000082 }, { 0x6, 0, 0, 0x00000074 }, { 0x6, 0, 0, 0x00000000 }, }; struct sock_fprog bpf = { #ifdef HAVE_NET_BPF_H .bf_len = sizeof(code) / sizeof(code[0]), .bf_insns = code, #else .len = sizeof(code) / sizeof(code[0]), .filter = code, #endif }; #ifdef HAVE_NET_BPF_H struct bpf_hdr *bpfh; #else char ethh[14] = {0}; char ipv6[48] = {0}; #endif unsigned int blen = 32767; test_log("query thread starting\n"); #ifdef HAVE_NET_BPF_H if_indextoname(ifx, ifr.ifr_name); raw = open("/dev/bpf", O_RDONLY); #endif #ifdef __linux__ raw = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); #endif if (raw == -1) { perror("socket(PF_PACKET)"); sem_post(&sem_query); return NULL; } #ifdef HAVE_NET_BPF_H if (ioctl(raw, BIOCGBLEN, &blen) == -1) { perror("ioctl(BIOCGBLEN)"); sem_post(&sem_query); goto exit_1; } buf = malloc((size_t)blen); if (!buf) { sem_post(&sem_query); goto exit_1; } if (ioctl(raw, BIOCSETIF, &ifr) == -1) { perror("ioctl(BIOCSETIF)"); sem_post(&sem_query); goto exit_1; } int opt = 1; if (ioctl(raw, BIOCIMMEDIATE, &opt)) { perror("ioctl(BIOCIMMEDIATE)"); sem_post(&sem_query); goto exit_1; } if (ioctl(raw, BIOCSETF, &bpf) == -1) { perror("ioctl(BIOCSETF)"); sem_post(&sem_query); goto exit_1; } #endif #ifdef __linux__ if (setsockopt(raw, SOL_SOCKET, SO_ATTACH_FILTER, &bpf, sizeof(bpf)) == -1) { perror("setsockopt(SO_ATTACH_FILTER)"); sem_post(&sem_query); return NULL; } #endif sem_post(&sem_query); /* socket ready, let main thread proceed */ #ifdef __linux__ /* prepare scatter/gather structs */ iov[0].iov_base = ðh; iov[0].iov_len = sizeof ethh; iov[1].iov_base = ipv6; iov[1].iov_len = sizeof ipv6; iov[2].iov_base = &mldh; iov[2].iov_len = sizeof mldh; msg.msg_name = buf; msg.msg_namelen = blen; msg.msg_iov = iov; msg.msg_iovlen = 3; msg.msg_flags = 0; #endif while (1) { test_log("query thread in loop\n"); #ifdef __linux__ byt = recvmsg(raw, &msg, 0); #endif #ifdef HAVE_NET_BPF_H byt = read(raw, buf, (size_t)blen); bpfh = (struct bpf_hdr *)buf; memcpy(&mldh, (char *)buf + bpfh->bh_hdrlen + 62, sizeof(struct mld_hdr)); #endif if (byt == -1) { perror("recvmsg"); break; } test_log("read %zi bytes\n", byt); test_assert(byt > 0, "%zi bytes received on PACKET socket", byt); if (byt > 0) { icmpv6 = &mldh.mld_icmp6_hdr; if (icmpv6->icmp6_type == MLD_LISTENER_QUERY) { char straddr[INET6_ADDRSTRLEN]; inet_ntop(AF_INET6, &mldh.mld_addr, straddr, INET6_ADDRSTRLEN); test_log("Query addr: %s\n", straddr); /* MLDv2 General Query */ if (!memcmp(&mldh.mld_addr, &allnodes, sizeof(struct in6_addr))) { q_gen++; } /* Multicast Address Specific Query */ else if (addr && !memcmp(&mldh.mld_addr, addr, sizeof(struct in6_addr))) { q_add++; } } } } free(buf); #ifdef HAVE_NET_BPF_H exit_1: #endif close(raw); test_log("query thread exiting\n"); return NULL; } #endif int main(void) { char name[] = "MLD listen thread"; #ifdef HAVE_LIBLIBRECAST mld_t *mld; lc_ctx_t *lctx; lc_socket_t *sock; lc_channel_t *chan; pthread_t tid_query; unsigned int ifx; int rc; test_cap_require(CAP_NET_RAW); test_name(name); test_require_net(TEST_NET_BASIC); ifx = get_multicast_if(); test_assert(ifx, "get_multicast_if() - find multicast capable interface"); if (!ifx) return TEST_WARN; mld = mld_init(0); test_assert(mld != NULL, "mld_t allocated"); if (!mld) return test_status; if (inet_pton(AF_INET6, MLD2_ALL_NODES, &allnodes) != 1) { perror("inet_pton (set allnodes)"); return test_status; } /* start query thread */ rc = sem_init(&sem_query, 0, 0); test_assert(rc == 0, "sem_init returned %i", rc); if (rc) goto err_mld_free; rc = pthread_create(&tid_query, NULL, thread_query, &ifx); test_assert(rc == 0, "pthread_create returned %i", rc); if (rc) goto err_sem_query_destroy; rc = sem_wait(&sem_query); test_assert(rc == 0, "sem_wait returned %i", rc); if (rc) goto err_sem_query_destroy; test_log("main thread: query thread is ready. Starting MLD\n"); if (!mld_start(mld)) { test_assert(0, "mld_start() failed: %s", strerror(errno)); goto err_sem_query_destroy; } /* ensure all threads created */ for (int i = 0; i < MLD_THREADS; i++) assert(mld->q[i]); /* MUST send MLD2 General Queries on startup - sleep, then check */ test_log("main thread sleeping\n"); usleep(100000); test_log("main thread awake\n"); test_assert(q_gen > 0, "MLD General Queries (%i)", q_gen); /* generate a random multicast address */ lctx = lc_ctx_new(); test_assert(lctx != NULL, "lc_ctx_new()"); if (!lctx) goto err_mld_stop; chan = lc_channel_random(lctx); test_assert(chan != NULL, "lc_channel_random()"); if (!chan) goto err_ctx_free; addr = lc_channel_in6addr(chan); test_assert(addr != NULL, "lc_channel_in6addr()"); if (!addr) goto err_ctx_free; /* check for group before joining */ rc = mld_filter_grp_cmp(mld, ifx, addr); test_assert(rc == 0, "check for group before joining on ifx %u", ifx); if (rc) goto err_ctx_free; /* JOIN group, check again */ sock = lc_socket_new(lctx); test_assert(sock != NULL, "lc_socket_new()"); if (!sock) goto err_ctx_free; rc = lc_socket_bind(sock, ifx); test_assert(rc == 0, "lc_socket_bind() returned %i", rc); if (rc) goto err_ctx_free; rc = lc_channel_bind(sock, chan); test_assert(rc == 0, "lc_channel_bind() returned %i", rc); if (rc) goto err_ctx_free; rc = lc_channel_join(chan); test_assert(rc == 0, "lc_channel_join() returned %i", rc); if (rc) goto err_ctx_free; /* does not receive MLD Address Specific Queries if this is < 2 on Linux */ sleep(2); rc = mld_filter_grp_cmp(mld, ifx, addr); test_assert(rc == 1, "check for group after joining on ifx %u", ifx); if (rc != 1) goto err_ctx_free; /* PART group */ rc = lc_channel_part(chan); test_assert(rc == 0, "lc_channel_part() returned %i", rc); if (rc != 0) goto err_ctx_free; usleep(10000); rc = mld_filter_grp_cmp(mld, ifx, addr); /* group is not removed from filter until timer expires */ test_assert(rc == 1, "group is still in filter after parting"); if (rc != 1) goto err_ctx_free; usleep(500000); /* ensure timer has been set to QRI */ struct timespec ts = {0}; struct timespec now = {0}; rc = mld_filter_timer_get(mld, ifx, addr, &ts); test_assert(rc == 1, "mld_filter_timer_get() returned %i", rc); if (rc != 1) goto err_ctx_free; rc = clock_gettime(CLOCK_REALTIME, &now); test_assert(rc == 0, "clock_gettime() returned %i", rc); if (rc) goto err_ctx_free; long int s = ts.tv_sec - now.tv_sec; /* allow timer to be within one second of expected value */ test_assert(s >= MLD2_QRI/1000 - 1 && s <= MLD2_QRI/1000, "timer set to QRI (=%lis) QRI = %i", s, MLD2_QRI / 1000); sleep(2); /* a good long snooze to make sure MLD Queries are all dealt with */ test_assert(q_add > 0, "MLD Address Specific Queries received (%i)", q_add); /* PART again, ensure no more Queries sent (max queries per QRI) */ q_add = 0; mld_filter_grp_part(mld, ifx, addr); usleep(10000); test_assert(q_add == 0, "ensure no MLD Queries received (QRI check) (%i)", q_add); /* set querier on ifx, ensure no MLD Query sent */ q_add = 0; mld_iface_t *iface; for (iface = mld->iface; iface; iface = iface->next) { if (iface->ifx == ifx) break; } test_assert(iface != NULL, "iface found"); if (iface) { mld_grp_list_t *g = mld_get_grp(mld, ifx, addr); if (g) { g->qlast.tv_sec = 0; /* clear QRI timer */ /* set timer as though another Querier is present */ clock_gettime(CLOCK_REALTIME, &iface->qseen); mld_filter_grp_part(mld, ifx, addr); usleep(10000); test_assert(q_add == 0, "another Querier present - ensure no MLD Queries received (%i)", q_add); } } // TODO build MLD Query with Link-Local source address lower than real // fe80:: (lowest possible link-local address) //msg = // link to win the Querier election // TODO check MLD is no longer Querier for the link // TODO check querier timer /* stop query thread */ pthread_cancel(tid_query); pthread_join(tid_query, NULL); err_ctx_free: lc_ctx_free(lctx); err_mld_stop: mld_stop(mld); err_sem_query_destroy: sem_destroy(&sem_query); err_mld_free: mld_free(mld); return test_status; #else return test_skip("%s - requires liblibrecast", name); #endif } librecast/libs/libmld/test/0000-0006.c000066400000000000000000000020311502456746400173200ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2022 Brett Sheffield */ #include "testnet.h" #include #include //void mld_query_handler(mld_t *mld, struct msghdr *msg); int main(void) { mld_t *mld; mld_msg_t msg = {0}; unsigned int ifx; int rc; test_name("mld_query_msg()"); test_require_net(TEST_NET_BASIC); ifx = get_multicast_if(); test_assert(ifx, "get_multicast_if() - find multicast capable interface"); if (!ifx) return TEST_WARN; mld = mld_init(0); test_assert(mld != NULL, "mld_t allocated"); rc = mld_query_msg(mld, ifx, NULL, &msg); test_assert(rc == 0, "mld_query_msg() returned %i", rc); struct icmp6_hdr *icmpv6 = msg.msgh.msg_iov[0].iov_base; test_assert(icmpv6->icmp6_type == MLD_LISTENER_QUERY, "icmp6_type = %i", icmpv6->icmp6_type); // TODO test Querier state // TODO win election, test Querier state // TODO set ifx via cmsg //mld_query_handler(mld, &msg.msgh); mld_query_msg_free(&msg); mld_free(mld); return test_status; } librecast/libs/libmld/test/0000-0007.c000066400000000000000000000054371502456746400173360ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2022-2025 Brett Sheffield */ #include "testnet.h" #ifdef HAVE_LIBLIBRECAST #include #endif #include #include #include #ifdef HAVE_LIBLIBRECAST static struct in6_addr *addr; static unsigned int ifx; static int watchcount; void watch_callback(mld_watch_t *watch) { test_assert(watch->ifx == ifx, "callback: ifx set"); aadd(&watchcount, 1); } #endif int main(void) { char name[] = "mld_watch_*()"; #ifdef HAVE_LIBLIBRECAST mld_t *mld; mld_watch_t *watch; lc_ctx_t *lctx; lc_channel_t *chan; int rc; test_cap_require(CAP_NET_RAW); test_name(name); test_require_net(TEST_NET_BASIC); ifx = get_multicast_if(); test_assert(ifx, "get_multicast_if() - find multicast capable interface"); if (!ifx) return TEST_WARN; mld = mld_init(0); test_assert(mld != NULL, "mld_t allocated"); if (!mld) return test_status; if (!mld_start(mld)) { test_assert(0, "mld_start() failed: %s", strerror(errno)); goto err_mld_free; } /* ensure all threads created */ for (int i = 0; i < MLD_THREADS; i++) assert(mld->q[i]); /* generate a random multicast address */ lctx = lc_ctx_new(); test_assert(lctx != NULL, "lc_ctx_new()"); chan = lc_channel_random(lctx); test_assert(chan != NULL, "lc_channel_random()"); addr = lc_channel_in6addr(chan); test_assert(addr != NULL, "lc_channel_in6addr()"); void *arg = mld; /* any arg will do */ int funwithflags = MLD_EVENT_JOIN; watch = mld_watch_add(mld, ifx, addr, watch_callback, arg, funwithflags); test_assert(watch != NULL, "watch set"); test_assert(watch->mld == mld, "watch: mld set"); test_assert(watch->ifx == ifx, "watch: ifx set"); test_assert(!memcmp(&watch->grp, addr, sizeof(struct in6_addr)), "watch: grp set"); test_assert(watch->arg == arg, "watch: arg set"); test_assert(watch->flags == funwithflags, "watch: flags set"); test_assert(watch->f == &watch_callback, "watch: callback function set"); mld_watch_del(watch); test_assert(mld->watch == NULL, "mld->watch == NULL"); /* add the watch again, we'll check with valgrind that the watch was * freed on mld_free() */ watch = mld_watch_add(mld, ifx, addr, watch_callback, arg, funwithflags); /* check for group before joining */ rc = mld_filter_grp_cmp(mld, ifx, addr); test_assert(rc == 0, "check for group before joining"); rc = mld_filter_grp_add(mld, ifx, addr); test_assert(rc == 0, "add group to filter"); usleep(10000); rc = mld_filter_grp_cmp(mld, ifx, addr); test_assert(rc == 1, "check for group after joining"); test_assert(aload(&watchcount) == 1, "ensure callback was triggered"); lc_ctx_free(lctx); mld_stop(mld); mld_free(mld); err_mld_free: return test_status; #else return test_skip("%s - requires liblibrecast", name); #endif } librecast/libs/libmld/test/0000-0008.c000066400000000000000000000077401502456746400173360ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2022-2025 Brett Sheffield */ #include "testnet.h" #ifdef HAVE_LIBLIBRECAST #include #endif #include #include #include #include #include #ifdef HAVE_LIBLIBRECAST static mld_t *mld; static struct in6_addr *addr; static unsigned int ifx; static sem_t sem; void *thread_mld_wait(void *arg) { int rc; int *waitcount = (int *)arg; rc = mld_wait(mld, ifx, addr, 0); if (rc == -1 && errno == EINTR) return NULL; /* mld_wait was interupted */ test_assert(rc == 0, "mld_wait() returns %i", rc); if (rc) test_log("%s (errno = %i)\n", strerror(errno), errno); (*waitcount)++; sem_post(&sem); return arg; } #endif int main(void) { char name[] = "mld_watch()"; #ifdef HAVE_LIBLIBRECAST pthread_t tid; lc_ctx_t *lctx; lc_channel_t *chan; struct timespec ts = {0}; int waitcount = 0; int rc; test_cap_require(CAP_NET_RAW); test_name(name); test_require_net(TEST_NET_BASIC); ifx = get_multicast_if(); test_assert(ifx, "get_multicast_if() - find multicast capable interface"); if (!ifx) return TEST_WARN; mld = mld_init(0); test_assert(mld != NULL, "mld_t allocated"); if (!mld) return test_status; if (!mld_start(mld)) { test_assert(0, "mld_start() failed: %s", strerror(errno)); goto err_mld_free; } /* ensure all threads created */ for (int i = 0; i < MLD_THREADS; i++) assert(mld->q[i]); /* generate a random multicast address */ lctx = lc_ctx_new(); test_assert(lctx != NULL, "lc_ctx_new()"); if (!lctx) goto err_mld_stop; chan = lc_channel_random(lctx); test_assert(chan != NULL, "lc_channel_random()"); if (!chan) goto err_ctx_free; addr = lc_channel_in6addr(chan); test_assert(addr != NULL, "lc_channel_in6addr()"); if (!addr) goto err_ctx_free; rc = sem_init(&sem, 0, 0); test_assert(rc == 0, "sem_init returned %i", rc); if (rc) goto err_ctx_free; /* ensure group s NOT in filter, or no point running test */ rc = mld_filter_grp_cmp(mld, ifx, addr); test_assert(rc == 0, "mld_filter_grp_cmp returned %i", rc); if (rc != 0) goto err_sem_destroy; /* mld_wait() will block unless MLD_DONTWAIT */ rc = pthread_create(&tid, NULL, thread_mld_wait, &waitcount); test_assert(rc == 0, "pthread_create returned %i", rc); if (rc) goto err_sem_destroy; rc = clock_gettime(CLOCK_REALTIME, &ts); test_assert(rc == 0, "clock_gettime returned %i", rc); if (rc) goto err_sem_destroy; ts.tv_sec++; /* timeout = 1s */ errno = 0, rc = sem_timedwait(&sem, &ts); test_assert(errno == ETIMEDOUT, "sem_wait() blocks without MLD_DONTWAIT"); test_assert(rc == -1, "sem_timedwait returned %i", rc); pthread_cancel(tid); pthread_join(tid, NULL); if (!rc) goto err_sem_destroy; /* MLD_DONTWAIT causes mld_wait() to be non-blocking */ errno = 0; rc = mld_wait(mld, ifx, addr, MLD_DONTWAIT); test_assert(errno == EWOULDBLOCK, "mld_wait() - EWOULDBLOCK"); test_assert(rc == -1, "mld_wait with MLD_DONTWAIT returns -1 - group not added"); /* now add a group to the filter */ rc = mld_filter_grp_add(mld, ifx, addr); test_assert(rc == 0, "add group to filter"); /* ensure group was added to filter, or no point running test */ rc = mld_filter_grp_cmp(mld, ifx, addr); test_assert(rc == 1, "mld_filter_grp_cmp returned %i", rc); if (rc != 1) goto err_sem_destroy; rc = mld_wait(mld, ifx, addr, 0); test_assert(rc == 0, "mld_wait() returns 0 when grp in filter"); waitcount = 0; pthread_create(&tid, NULL, thread_mld_wait, &waitcount); test_assert(rc == 0, "pthread_create returned %i", rc); if (rc) goto err_sem_destroy; sem_wait(&sem); test_assert(rc == 0, "sem_wait() blocks, then returns when grp added"); pthread_cancel(tid); pthread_join(tid, NULL); test_assert(waitcount == 1, "waitcount = %i", waitcount); err_sem_destroy: sem_destroy(&sem); err_ctx_free: lc_ctx_free(lctx); err_mld_stop: mld_stop(mld); err_mld_free: mld_free(mld); return test_status; #else return test_skip("%s - requires liblibrecast", name); #endif } librecast/libs/libmld/test/0000-0009.c000066400000000000000000000042261502456746400173330ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2022-2025 Brett Sheffield */ #include "testnet.h" #ifdef HAVE_LIBLIBRECAST #include #include #endif #include #include #include #ifdef HAVE_LIBLIBRECAST static unsigned int ifx; static unsigned int tapifx; static volatile int ifup; static volatile int ifdown; void watch_callback_ifup(mld_watch_t *watch) { if (mld_watch_ifx(watch) == aload(&tapifx)) aadd(&ifup, 1); } void watch_callback_ifdown(mld_watch_t *watch) { if (mld_watch_ifx(watch) == aload(&tapifx)) aadd(&ifdown, 1); } #endif int main(void) { char name[] = "mld_watch_*() - netlink events"; #ifdef HAVE_LIBLIBRECAST mld_t *mld; mld_watch_t *watch; lc_ctx_t *lctx; char ifname[IFNAMSIZ] = {0}; int rc, fd; test_require_linux(); /* requires netlink */ test_cap_require(CAP_NET_RAW); test_name(name); ifx = get_multicast_if(); test_assert(ifx, "get_multicast_if() - find multicast capable interface"); if (!ifx) return TEST_WARN; mld = mld_init(0); test_assert(mld != NULL, "mld_t allocated"); mld_start(mld); /* ensure all threads created */ for (int i = 0; i < MLD_THREADS; i++) assert(mld->q[i]); void *arg = mld; /* any arg will do */ watch = mld_watch_add(mld, 0, NULL, watch_callback_ifup, arg, MLD_EVENT_IFUP); watch = mld_watch_add(mld, 0, NULL, watch_callback_ifdown, arg, MLD_EVENT_IFDOWN); test_assert(watch != NULL, "watch set"); lctx = lc_ctx_new(); fd = lc_tap_create(ifname); astor(&tapifx, if_nametoindex(ifname)); rc = lc_link_set(lctx, ifname, 1); test_assert(rc == 0, "bring up interface"); sleep(2); /* this can take a *while* */ int _ifup = aload(&ifup); test_assert(_ifup == 1, "MLD_EVENT_IFUP: ensure callback was triggered (%i)", _ifup); rc = lc_link_set(lctx, ifname, 0); sleep(1); test_assert(rc == 0, "bring down interface"); int _ifdown = aload(&ifdown); test_assert(_ifdown == 1, "MLD_EVENT_IFDOWN: ensure callback was triggered (%i)", _ifdown); close(fd); lc_ctx_free(lctx); mld_stop(mld); mld_free(mld); return test_status; #else return test_skip("%s - requires liblibrecast", name); #endif } librecast/libs/libmld/test/0000-0010.c000066400000000000000000000013441502456746400173210ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2023 Brett Sheffield */ #include "testnet.h" #include "testdata.h" #define NTHREADS 2 #define MAXJOBS 256 void *thread_job(void *arg) { char buf[BUFSIZ]; test_random_bytes(buf, sizeof buf); return arg; } int main(void) { job_queue_t *q; job_t *job[MAXJOBS] = {0}; test_name("job tests"); q = job_queue_create(NTHREADS); test_assert(q != NULL, "job_queue_create(%i)", NTHREADS); for (int i = 0; i < MAXJOBS; i++) { job[i] = job_push_new(q, thread_job, NULL, 0, NULL, 0); test_assert(job[i] != NULL, "job[%i] created", i); if (!job[i]) { perror("job_push_new"); break; } } job_queue_destroy(q); return test_status; } librecast/libs/libmld/test/Makefile.in000066400000000000000000000067501502456746400202730ustar00rootroot00000000000000# SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only # Copyright (c) 2017-2024 Brett Sheffield TESTRUNNER := @TESTRUNNER@ CFLAGS := @CFLAGS@ override CFLAGS += @LIBRECAST_CFLAGS@ -fno-builtin-malloc -fno-builtin-calloc -I../src -I../include CPPFLAGS := @CPPFLAGS@ FALSE := @FALSE@ TEST_SOURCES := $(wildcard ????-????.c) TEST_PROGS ?= $(TEST_SOURCES:.c=.test) TEST_MULTICAST_Linux := ip route get ff1e:: 2> /dev/null | wc -l TEST_MULTICAST_FreeBSD := case $$(route -6 get ff1e:: 2> /dev/null) in *REJECT*) echo 0;; *DONE*) echo 1;; *) echo 0 ;; esac TEST_MULTICAST_NetBSD := case $$(/sbin/route -n get -inet6 ff1e:: 2>/dev/null) in *REJECT*) echo 0;; *DONE*) echo 1;; *) echo 0 ;; esac TEST_MULTICAST_OpenBSD := case $$(route -n get -inet6 ff1e:: 2> /dev/null) in *REJECT*) echo 0;; *DONE*) echo 1;; *) echo 0 ;; esac TEST_MULTICAST_OUT = $(shell $(TEST_MULTICAST) || /bin/true) TEST_MULTICAST = $(TEST_MULTICAST_$(shell uname -s)) LDFLAGS := -L../src -Wl,-rpath,../src @LDFLAGS@ @LIBRECAST_LDFLAGS@ LDLIBS = @LIBS@ @LIBMLD@ OBJS := test.o testdata.o testnet.o misc.o LASTLOG := lastlog.log LOGFILE := $(shell mktemp "testlog-XXXXXX") ANSI_RESET = "\033[0m" ANSI_BOLD := "\033[0m\033[2m" ANSI_GREEN = "\033[32m" ANSI_RED = "\033[31m" ANSI_YELLOW = "\033[33m" ANSI_WHITE = "\033[37m" PASS = $(ANSI_RESET)$(ANSI_GREEN)\ OK$(ANSI_RESET) WARN = $(ANSI_RESET)$(ANSI_YELLOW)WARN$(ANSI_RESET) FAIL = $(ANSI_RESET)$(ANSI_RED)FAIL$(ANSI_RESET) UNKN = $(ANSI_RESET)$(ANSI_WHITE)????$(ANSI_RESET) VALGRIND = valgrind --leak-check=full --max-stackframe=20480160 --error-exitcode=2 --errors-for-leak-kinds=all --track-origins=yes define runtest = export HAVE_MULTICAST_ROUTES="$(TEST_MULTICAST_OUT)" @printf $(ANSI_BOLD) @echo -n " $(1:.test=) " @echo "================================================================================" >>$(LOGFILE) @echo "`date +"%Y-%m-%d %H:%M:%S"` test begins" >>$(LOGFILE) @echo "--------------------------------------------------------------------------------" >>$(LOGFILE) @echo -n "===> TEST $(1:.test=) " >>$(LOGFILE) @$(MEMCHECK) ./$(1) 2>>$(LOGFILE) ret=$$? @echo "--------------------------------------------------------------------------------" >>$(LOGFILE) @echo "`date +"%Y-%m-%d %H:%M:%S"` test ends" >>$(LOGFILE) @if [ $$ret -eq 0 ]; then \ printf $(PASS); echo; \ elif [ $$ret -eq 1 ]; then \ printf $(WARN); echo; \ elif [ $$ret -eq 2 ]; then \ printf $(FAIL); echo; \ fails=$$(( fails + 1 )) ; \ else \ printf $(UNKN); echo; \ fails=$$(( fails + 1 )) ; \ fi $(eval tests_run=$(shell echo $$(($(tests_run)+1)))) endef .PHONY: test clean test: $(TESTRUNNER) %.test: %.c $(OBJS) $(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) -o $@ $< $(OBJS) $(LDLIBS) lctest: $(TEST_PROGS) lctest -b $^ memcheck: MEMCHECK="$(VALGRIND)" $(MAKE) test memcheck/%: MEMCHECK="$(VALGRIND)" $(MAKE) test/$(@F) # if $(@F) is a directory, run tests in that directory test/%: @if [ -d "$(@F)" ]; then $(eval TEST_PROGS=$(notdir $(wildcard $(@F)/*.test))) TEST_PROGS="$(TEST_PROGS)" $(MAKE) maketest else $(eval TEST_PROGS=0000-$(@F).test) TEST_PROGS="$(TEST_PROGS)" $(MAKE) maketest fi .ONESHELL: maketest maketest: $(TEST_PROGS) @fails=0 ln -sf $(LOGFILE) $(LASTLOG) $(foreach x,$^,$(call runtest,$(x))) @echo -e "\n$(TIMESTAMP) - tests done" >> $(LOGFILE) @echo -e "$(tests_run) tests run\nlogfile: $(LOGFILE)\n" @if [ $$fails -gt 0 ]; then \ echo ", $$fails tests failed"; \ $(FALSE); else echo fi clean: $(RM) *.o *.test testlog-?????? $(LASTLOG) realclean: clean $(RM) Makefile librecast/libs/libmld/test/all/000077500000000000000000000000001502456746400167665ustar00rootroot00000000000000librecast/libs/libmld/test/all/0000-0000.test000077700000000000000000000000001502456746400226662../0000-0000.testustar00rootroot00000000000000librecast/libs/libmld/test/all/0000-0001.test000077700000000000000000000000001502456746400226702../0000-0001.testustar00rootroot00000000000000librecast/libs/libmld/test/all/0000-0002.test000077700000000000000000000000001502456746400226722../0000-0002.testustar00rootroot00000000000000librecast/libs/libmld/test/all/0000-0003.test000077700000000000000000000000001502456746400226742../0000-0003.testustar00rootroot00000000000000librecast/libs/libmld/test/all/0000-0004.test000077700000000000000000000000001502456746400226762../0000-0004.testustar00rootroot00000000000000librecast/libs/libmld/test/all/0000-0005.test000077700000000000000000000000001502456746400227002../0000-0005.testustar00rootroot00000000000000librecast/libs/libmld/test/all/0000-0006.test000077700000000000000000000000001502456746400227022../0000-0006.testustar00rootroot00000000000000librecast/libs/libmld/test/all/0000-0007.test000077700000000000000000000000001502456746400227042../0000-0007.testustar00rootroot00000000000000librecast/libs/libmld/test/all/0000-0008.test000077700000000000000000000000001502456746400227062../0000-0008.testustar00rootroot00000000000000librecast/libs/libmld/test/all/0000-0009.test000077700000000000000000000000001502456746400227102../0000-0009.testustar00rootroot00000000000000librecast/libs/libmld/test/falloc.c000066400000000000000000000027641502456746400176330ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2021-2022 Brett Sheffield */ #define _GNU_SOURCE #include #include #include #include #include static volatile int allock; static size_t stackptr; static char stackbuf[1024]; static void *(*_malloc)(size_t); static void (*_free)(void *); static int falloc_fail = -1; /* *alloc fails when zero - decremented each allocation */ static void *falloc_enomem(void) { fprintf(stderr, "falloc forcing ENOMEM\n"); errno = ENOMEM; return NULL; } void *malloc(size_t size) { if (allock) { /* thanks to FatalFlaw for the idea * https://stackoverflow.com/questions/6083337/overriding-malloc-using-the-ld-preload-mechanism */ /* dlsym calls calloc() - hand it a block from our stack */ void *p; p = stackbuf + stackptr; stackptr += size; return p; } else if (!_malloc) { allock = 1; *(void **)&_malloc = dlsym(RTLD_NEXT, "malloc"); *(void **)&_free = dlsym(RTLD_NEXT, "free"); allock = 0; } if (falloc_fail > 0) falloc_fail--; if (!falloc_fail) return falloc_enomem(); return _malloc(size); } void *calloc(size_t nmemb, size_t size) { void *ptr; size_t sz = nmemb * size; ptr = malloc(sz); if (!ptr) return NULL; memset(ptr, 0, sz); return ptr; } void free(void *ptr) { if (!ptr) return; if ((char *)ptr < stackbuf || (char *)ptr > stackbuf + sizeof stackbuf) _free(ptr); } void falloc_setfail(int failafter) { falloc_fail = failafter; } librecast/libs/libmld/test/falloc.h000066400000000000000000000007721502456746400176350ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2021,2023 Brett Sheffield */ /* wrappers for *alloc */ __attribute__((malloc)) __attribute__((alloc_size(1,2))) void *calloc(size_t nmemb, size_t size); __attribute__((malloc)) __attribute__((alloc_size(1))) void *malloc(size_t size); /* set *alloc calls to force failure with ENOMEM after failafter allocations. * Set failafter to -1 to never force fail (default) */ void falloc_setfail(int failafter); librecast/libs/libmld/test/misc.c000066400000000000000000000003371502456746400173200ustar00rootroot00000000000000#include #include #include "misc.h" int _vscprintf (const char * format, va_list argp) { int r; va_list argc; va_copy(argc, argp); r = vsnprintf(NULL, 0, format, argc); va_end(argc); return r; } librecast/libs/libmld/test/misc.h000066400000000000000000000003141502456746400173200ustar00rootroot00000000000000#ifndef __LIBRECAST_MISC_H__ #define __LIBRECAST_MISC_H__ 1 /* return size of buffer to allocate for vsnprintf() */ int _vscprintf (const char * format, va_list argp); #endif /* __LIBRECAST_MISC_H__ */ librecast/libs/libmld/test/test.c000066400000000000000000000114451502456746400173460ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2020-2023 Brett Sheffield */ #include "test.h" #include #include #include #include #include #include #define DEFAULT_TERM_COLS 80 #define TESTID_WIDTH 16 #define SPINAL_TAP 11 int COLS = DEFAULT_TERM_COLS; int MSGW; int test_status = TEST_OK; /* test exit status (not a count of failures) */ int capreqd = 0; int capfail = 0; sem_t log_lock; static int _vscprintf (const char * format, va_list argp) { int r; va_list argc; va_copy(argc, argp); r = vsnprintf(NULL, 0, format, argc); va_end(argc); return r; } void vfail_msg(char *msg, va_list argp) { char *b; b = malloc(_vscprintf(msg, argp) + 1); vsprintf(b, msg, argp); printf("\n%-*s%-*s", SPINAL_TAP, " ", MSGW, b); free(b); test_status = TEST_FAIL; } int test_assert(int condition, char *msg, ...) { char *b; va_list argp, copy; va_start(argp, msg); va_copy(copy, argp); b = malloc(_vscprintf(msg, argp) + 6); if (b) vsprintf(b, msg, copy); if (!condition) { vfail_msg(msg, argp); if (b) test_log("[FAIL] %s\n", b); } else if (b) { test_log("[ OK ] %s\n", b); } free(b); va_end(argp); return condition; } int test_strcmp(char *str1, char *str2, char *msg, ...) { if (str1 == NULL || str2 == NULL || strcmp(str1, str2)) { va_list argp; va_start(argp, msg); vfail_msg(msg, argp); va_end(argp); return 0; } return 1; } int test_strncmp(char *str1, char *str2, size_t len, char *msg, ...) { if (str1 == NULL || str2 == NULL || strncmp(str1, str2, len)) { va_list argp; va_start(argp, msg); vfail_msg(msg, argp); va_end(argp); return 0; } return 1; } int test_expect(char *expected, char *got) { return test_strcmp(expected, got, "expected: '%s', got: '%s'", expected, got); } int test_expectn(char *expected, char *got, size_t len) { return test_strncmp(expected, got, len, "expected: '%s', got: '%s'", expected, got); } void test_log(char *msg, ...) { char *b; va_list argp; va_start(argp, msg); b = malloc(_vscprintf(msg, argp) + 1); vsprintf(b, msg, argp); sem_wait(&log_lock); fprintf(stderr, "%s", b); fflush(stderr); sem_post(&log_lock); va_end(argp); free(b); } static void init_terminal(void) { #if HAVE_SYS_IOCTL_H if (isatty(fileno(stdout))) { /* get terminal size */ struct winsize w; COLS = (ioctl(fileno(stdout), TIOCGWINSZ, &w) != -1) ? w.ws_col : DEFAULT_TERM_COLS; } else COLS = DEFAULT_TERM_COLS; #endif MSGW = COLS - TESTID_WIDTH; } void test_init(void) { static int runonce; if (runonce++) return; init_terminal(); sem_init(&log_lock, 0, 1); } void test_name(char *str, ...) { char *b; va_list argp; int do_exit = 1; test_init(); va_start(argp, str); b = malloc(_vscprintf(str, argp) + 1); vsprintf(b, str, argp); test_log(" %s\n", b); test_log("\n"); if (capfail) { printf("%-*s", MSGW, "----- requires capabilities (skipping) -----"); } else if (!capreqd && geteuid() == 0) { printf("%-*s", MSGW, "----- does not require root (skipping) -----"); } else if (test_status != TEST_OK) { printf("%-*s", MSGW, "----- (skipping) -----"); } else { printf("%-*s", MSGW, b); do_exit ^= do_exit; } fflush(stdout); /* ensure the test name is displayed in case of SIGABORT */ va_end(argp); free(b); if (do_exit) exit(test_status); } int test_skip(char *str, ...) { char *b; va_list argp; init_terminal(); sem_init(&log_lock, 0, 1); va_start(argp, str); b = malloc(_vscprintf(str, argp) + 1); vsprintf(b, str, argp); printf("(skipped) %-*s", MSGW - 10, b); test_log(" %s\n", b); test_log("\n"); va_end(argp); free(b); return TEST_WARN; } void test_rusage(void) { struct rusage ru = {0}; if (getrusage(RUSAGE_SELF, &ru)) { perror("getrusage"); return; } test_log("user : %lis.%li\n", ru.ru_utime.tv_sec, ru.ru_utime.tv_usec); test_log("system: %lis.%li\n", ru.ru_stime.tv_sec, ru.ru_stime.tv_usec); test_log("maxrss: %li\n", ru.ru_maxrss); test_log("ixrss: %li\n", ru.ru_ixrss); test_log("idrss: %li\n", ru.ru_idrss); test_log("isrss: %li\n", ru.ru_isrss); test_log("minflt: %li\n", ru.ru_minflt); test_log("majflt: %li\n", ru.ru_majflt); test_log("nswap: %li\n", ru.ru_nswap); test_log("inblock: %li\n", ru.ru_inblock); test_log("oublock: %li\n", ru.ru_oublock); test_log("msgsnd: %li\n", ru.ru_msgsnd); test_log("msgrcv: %li\n", ru.ru_msgrcv); test_log("nsignals: %li\n", ru.ru_nsignals); test_log("nvcsw: %li\n", ru.ru_nvcsw); test_log("nivcsw: %li\n", ru.ru_nivcsw); } void test_cap_require(int cap) { (void) cap; // TODO check for capabilities on Linux if (geteuid()) capfail++; capreqd++; } void test_require_linux(void) { #ifndef __linux__ init_terminal(); printf("%-*s", MSGW, "----- linux only (skipping) -----"); exit(test_status); #endif } librecast/libs/libmld/test/test.h000066400000000000000000000022501502456746400173450ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2020-2022 Brett Sheffield */ #ifndef _TEST_H #define _TEST_H 1 #ifdef __linux__ # define _GNU_SOURCE #endif #include "../src/config.h" #include #include #include #include #include #include "valgrind.h" #if HAVE_SYS_ENDIAN_H # include #endif #ifdef __linux__ #include #else #define CAP_NET_ADMIN 12 #define CAP_NET_RAW 13 #endif enum { TEST_ERR = -1, TEST_OK = 0, TEST_WARN = 1, TEST_FAIL = 2, TEST_UNKN = 3 }; extern int test_status; void test_init(void); void fail_msg(char *msg, ...); int test_assert(int condition, char *msg, ...); int test_assert_q(int condition, char *msg, ...); int test_strcmp(char *str1, char *str2, char *msg, ...); int test_strncmp(char *str1, char *str2, size_t len, char *msg, ...); int test_expect(char *expected, char *got); int test_expectn(char *expected, char *got, size_t len); void test_log(char *msg, ...); void test_name(char *str, ...); int test_skip(char *str, ...); void test_cap_require(int cap); void test_require_linux(void); #endif /* _TEST_H */ librecast/libs/libmld/test/testdata.c000066400000000000000000000071241502456746400201770ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2023-2025 Brett Sheffield */ #include "testdata.h" #ifdef HAVE_LIBLIBRECAST static size_t getbufsize(void) { int buflen = sysconf(_SC_PAGESIZE); return (size_t)(16 * buflen); } #endif int test_random_bytes(void *ptr, size_t sz) { FILE *fr; size_t byt = 0, bi; fr = fopen("/dev/urandom", "r"); if (!fr) return -1; while (byt < sz) { bi = fread(ptr, 1, sz - byt, fr); if (bi > 0) { byt += bi; ptr = (char *)ptr + bi; } } fclose(fr); return 0; } int test_sparsify_fd(int fd, size_t sz) { FILE *f; int fdup; fdup = dup(fd); f = fdopen(fdup, "r+"); if (!f) return -1; fseek(f, sz - 1, SEEK_SET); fputc(0, f); fclose(f); return 0; } static int test_randomize_file(int fd, size_t sz) { FILE *f, *fr; char buf[BUFSIZ]; size_t byt = 0, bi; int fdup; fdup = dup(fd); f = fdopen(fdup, "w+"); if (!f) return -1; fr = fopen("/dev/urandom", "r"); if (!fr) goto exit_0; while (byt < sz) { bi = fread(buf, 1, MIN(sizeof buf, sz - byt), fr); if (bi > 0) { byt += fwrite(buf, 1, bi, f); } } fclose(fr); exit_0: fclose(f); return 0; } int test_data_file(char *filename, size_t sz, int flags) { int fd; if (flags & TEST_TMP) { if ((fd = mkstemp(filename)) == -1) { perror("mkstemp"); return -1; } } else if ((fd = open(filename, flags)) == -1) { perror("open"); return -1; } if (flags & TEST_RND) { if (test_randomize_file(fd, sz) == -1) { close(fd); return -1; } } else if (sz > 0) { /* size requested, but no data => sparse */ if (test_sparsify_fd(fd, sz) == -1) { close(fd); return -1; } } return fd; } int test_data_size(char *filename, size_t sz) { struct stat sb; if (stat(filename, &sb) == -1) return -1; if ((sb.st_mode & S_IFMT) != S_IFREG) return -1; if ((size_t)sb.st_size != sz) return -1; return 0; } #ifdef HAVE_LIBLIBRECAST int test_hash_file(const char *filename, unsigned char *hash, size_t hashlen, char *buf, size_t buflen) { hash_state state; FILE *f; size_t byt; int free_buf = (buf == NULL); /* was buffer provided ? */ if (!buf) { buflen = getbufsize(); buf = malloc(buflen); if (!buf) return -1; } f = fopen(filename, "r"); if (!f) goto exit_0; hash_init(&state, NULL, 0, hashlen); while ((byt = fread(buf, 1, buflen, f))) { hash_update(&state, (unsigned char *)buf, byt); } hash_final(&state, hash, hashlen); fclose(f); exit_0: if (free_buf) free(buf); return 0; } int test_file_match(const char *file1, const char *file2) { unsigned char hash[2][HASHSIZE]; char buf[BUFSIZ]; memset(hash, 0, sizeof hash); test_hash_file(file1, hash[0], HASHSIZE, buf, sizeof buf); test_hash_file(file2, hash[1], HASHSIZE, buf, sizeof buf); fprintf(stderr, "%s: ", file1); hash_hex_debug(stderr, hash[0], HASHSIZE); fprintf(stderr, "%s: ", file2); hash_hex_debug(stderr, hash[1], HASHSIZE); return memcmp(hash[0], hash[1], HASHSIZE); } #endif int test_file_scratch(const char *filename, long offset, size_t len) { char *buf; FILE *f, *fr; size_t byt = 0, bi; int buflen = MIN(getpagesize(), (int)len); if (!len) return 0; f = fopen(filename, "r+"); if (!f) return -1; fr = fopen("/dev/urandom", "r"); if (!fr) goto exit_0; if (offset < 0) { if (fseek(f, offset, SEEK_END) == -1) goto exit_1; } else if (offset > 0) { if (fseek(f, offset, SEEK_SET) == -1) goto exit_1; } buf = malloc(buflen); if (!buf) goto exit_1; while (byt < len) { bi = fread(buf, 1, MIN((size_t)buflen, len - byt), fr); if (bi > 0) { byt += fwrite(buf, 1, bi, f); } } free(buf); exit_1: fclose(fr); exit_0: fclose(f); return 0; } librecast/libs/libmld/test/testdata.h000066400000000000000000000034141502456746400202020ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2023-2025 Brett Sheffield */ #ifndef _TESTDATA_H #define _TESTDATA_H 1 #include #ifdef HAVE_LIBLIBRECAST #include #endif #include #include #include #include #include #include #include enum { TEST_TMP = 1, TEST_RND = 2, }; /* write sz random bytes to ptr */ int test_random_bytes(void *ptr, size_t sz); /* create test file with of sz bytes at path filename * * flags: * TEST_TMP - if set, a temp file is created using filename as the template. * TEST_RND - fill the file with sz random bytes * * if sz > 0 but TEST_RND is not set, a sparse file is created. */ int test_data_file(char *filename, size_t sz, int flags); /* verify filename is a regular file and is correct size * return 0 if correct, -1 on error */ int test_data_size(char *filename, size_t sz); /* hash file * filename - file to hash * hash - buffer to return hash in * hashlen - length of hash buffer * buf - either NULL or a pointer to a preallocated buffer for file I/O * buflen - length of buf in bytes * returns 0 on success, -1 on error, setting errno */ int test_hash_file(const char *filename, unsigned char *hash, size_t hashlen, char *buf, size_t buflen); /* hash files and confirm data matches, return 0 on match, nonzero fail */ int test_file_match(const char *file1, const char *file2); /* write len random bytes to file, starting at offset off * returns 0 on success, -1 on error, setting errno */ int test_file_scratch(const char *filename, long offset, size_t len); /* extend file sparsely to sz bytes */ int test_sparsify_fd(int fd, size_t sz); #endif /* _TESTDATA_H */ librecast/libs/libmld/test/testnet.c000066400000000000000000000071571502456746400200620ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2022-2023 Brett Sheffield */ #include "test.h" #include #include #ifdef __linux__ #ifdef HAVE_LIBLIBRECAST # include # include #endif #endif #include #include #include #ifndef AF_LINK # ifdef AF_PACKET # define AF_LINK AF_PACKET # endif #endif unsigned int get_invalid_ifx(void) { char ifname[IF_NAMESIZE]; for (unsigned int ifx = 1; ifx < UINT_MAX; ifx++) { if (!if_indextoname(ifx, ifname)) return ifx; } return 0; } /* find an interface that supports multicast */ unsigned get_multicast_if(void) { unsigned ifidx = 0; /* create tap interface and bring it up */ char ifname[IFNAMSIZ] = {0}; #ifdef __linux__ #ifdef HAVE_LIBLIBRECAST lc_tuntap_create(ifname, IFF_TAP | IFF_NO_PI); lc_ctx_t *lctx = lc_ctx_new(); lc_link_set(lctx, ifname, 1); lc_ctx_free(lctx); ifidx = if_nametoindex(ifname); #endif #endif if (!ifidx) { test_log("unable to create tap device: %s\n", strerror(errno)); /* failed to create tap, find multicast capable interface */ struct ifaddrs *ifa = NULL, *ifap = NULL; test_assert(getifaddrs(&ifa) != -1, "getifaddrs(): %s", strerror(errno)); for (ifap = ifa; ifap; ifap = ifap->ifa_next) { if (!(ifap->ifa_flags & IFF_MULTICAST)) continue; /* we don't want the loopback interface */ if (ifap->ifa_flags & IFF_LOOPBACK) continue; if (ifap->ifa_addr == NULL) continue; if (ifap->ifa_addr->sa_family != AF_INET6) continue; ifidx = if_nametoindex(ifap->ifa_name); test_log("found multicast interface %s [%u]\n", ifap->ifa_name, ifidx); break; } freeifaddrs(ifa); } else { test_log("tap %s created\n", ifname); } return ifidx; } int test_net_level(void) { struct ifaddrs *ifaddr; int ifaces = 0; int ifup = 0; int mcast = 0; int addr6 = 0; int addr4 = 0; int level = 0; int mroutes = 0; char * have_multicast = getenv("HAVE_MULTICAST_ROUTES"); test_init(); test_log("Checking network connectivity...\n"); if (getifaddrs(&ifaddr) == -1) return -1; for (struct ifaddrs *ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) { switch (ifa->ifa_addr->sa_family) { case AF_LINK: ifaces++; if (ifa->ifa_flags & IFF_UP) { ifup++; /* test MULTICAST flag, skip loopback interfaces */ if (ifa->ifa_flags & IFF_LOOPBACK) break; if (ifa->ifa_flags & IFF_MULTICAST) mcast++; } break; case AF_INET6: if (ifa->ifa_flags & IFF_UP) addr6++; break; case AF_INET: if (ifa->ifa_flags & IFF_UP) addr4++; break; } } freeifaddrs(ifaddr); test_log("have_multicast: %s\n", have_multicast); if (have_multicast) mroutes = atoi(have_multicast); test_log(" %i network interfaces found\n", ifaces); test_log(" %i network interfaces up\n", ifup); test_log(" %i MULTICAST interfaces up\n", mcast); test_log(" %i IPv6 addresses\n", addr6); test_log(" %i IPv4 addresses\n", addr4); test_log(" %i multicast routes\n", mroutes); level |= (ifaces > 0); level |= (ifup > 0) << 1; level |= (addr4 > 0) << 2; level |= (addr6 > 0) << 3; level |= (mcast > 0) << 4; level |= (mroutes > 0) << 5; test_log("connectivity level = %i (%06b)\n", level, level); return level; } int test_require_net(int required) { int lvl = test_net_level(); if ((lvl & required) != required) { test_log("------------------------------------------------------\n"); test_log("Required network level not met. Skipping test. \n"); test_log("(%06b/%06b)\n", lvl, required); test_log("------------------------------------------------------\n"); exit(TEST_WARN); } return lvl; } librecast/libs/libmld/test/testnet.h000066400000000000000000000021501502456746400200530ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2022-2023 Brett Sheffield */ #include "test.h" #include #include #include #include /* levels of network availability. Each level requires the previous */ enum { TEST_NET_NONE = 0, /* no network interfaces detected */ TEST_NET_IFACE = 1,/* at least one interface detected */ TEST_NET_UP = 2, /* at least one interface is up */ TEST_NET_ADDR4 = 4, /* IPv4 network address found */ TEST_NET_ADDR6 = 8, /* IPv6 network address found */ TEST_NET_MCAST = 16,/* device with MULTICAST flag set found */ TEST_NET_MROUTE = 32 /* has multicast routes */ }; #define TEST_NET_BASIC TEST_NET_IFACE | TEST_NET_UP | TEST_NET_ADDR6 | TEST_NET_MCAST | TEST_NET_MROUTE /* find an invalid interface index */ unsigned int get_invalid_ifx(void); /* find an interface that supports multicast */ unsigned get_multicast_if(void); /* return level of network available */ int test_net_level(void); /* exit test with TEST_WARN unless network level is met */ int test_require_net(int required); librecast/libs/libmld/test/valgrind.h000066400000000000000000014713751502456746400202170ustar00rootroot00000000000000/* -*- c -*- ---------------------------------------------------------------- Notice that the following BSD-style license applies to this one file (valgrind.h) only. The rest of Valgrind is licensed under the terms of the GNU General Public License, version 2, unless otherwise indicated. See the COPYING file in the source distribution for details. ---------------------------------------------------------------- This file is part of Valgrind, a dynamic binary instrumentation framework. Copyright (C) 2000-2017 Julian Seward. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 3. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 4. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------- Notice that the above BSD-style license applies to this one file (valgrind.h) only. The entire rest of Valgrind is licensed under the terms of the GNU General Public License, version 2. See the COPYING file in the source distribution for details. ---------------------------------------------------------------- */ /* This file is for inclusion into client (your!) code. You can use these macros to manipulate and query Valgrind's execution inside your own programs. The resulting executables will still run without Valgrind, just a little bit more slowly than they otherwise would, but otherwise unchanged. When not running on valgrind, each client request consumes very few (eg. 7) instructions, so the resulting performance loss is negligible unless you plan to execute client requests millions of times per second. Nevertheless, if that is still a problem, you can compile with the NVALGRIND symbol defined (gcc -DNVALGRIND) so that client requests are not even compiled in. */ #ifndef __VALGRIND_H #define __VALGRIND_H /* ------------------------------------------------------------------ */ /* VERSION NUMBER OF VALGRIND */ /* ------------------------------------------------------------------ */ /* Specify Valgrind's version number, so that user code can conditionally compile based on our version number. Note that these were introduced at version 3.6 and so do not exist in version 3.5 or earlier. The recommended way to use them to check for "version X.Y or later" is (eg) #if defined(__VALGRIND_MAJOR__) && defined(__VALGRIND_MINOR__) \ && (__VALGRIND_MAJOR__ > 3 \ || (__VALGRIND_MAJOR__ == 3 && __VALGRIND_MINOR__ >= 6)) */ #define __VALGRIND_MAJOR__ 3 #define __VALGRIND_MINOR__ 16 #include /* Nb: this file might be included in a file compiled with -ansi. So we can't use C++ style "//" comments nor the "asm" keyword (instead use "__asm__"). */ /* Derive some tags indicating what the target platform is. Note that in this file we're using the compiler's CPP symbols for identifying architectures, which are different to the ones we use within the rest of Valgrind. Note, __powerpc__ is active for both 32 and 64-bit PPC, whereas __powerpc64__ is only active for the latter (on Linux, that is). Misc note: how to find out what's predefined in gcc by default: gcc -Wp,-dM somefile.c */ #undef PLAT_x86_darwin #undef PLAT_amd64_darwin #undef PLAT_x86_win32 #undef PLAT_amd64_win64 #undef PLAT_x86_linux #undef PLAT_amd64_linux #undef PLAT_ppc32_linux #undef PLAT_ppc64be_linux #undef PLAT_ppc64le_linux #undef PLAT_arm_linux #undef PLAT_arm64_linux #undef PLAT_s390x_linux #undef PLAT_mips32_linux #undef PLAT_mips64_linux #undef PLAT_nanomips_linux #undef PLAT_x86_solaris #undef PLAT_amd64_solaris #if defined(__APPLE__) && defined(__i386__) # define PLAT_x86_darwin 1 #elif defined(__APPLE__) && defined(__x86_64__) # define PLAT_amd64_darwin 1 #elif (defined(__MINGW32__) && defined(__i386__)) \ || defined(__CYGWIN32__) \ || (defined(_WIN32) && defined(_M_IX86)) # define PLAT_x86_win32 1 #elif (defined(__MINGW32__) && defined(__x86_64__)) \ || (defined(_WIN32) && defined(_M_X64)) /* __MINGW32__ and _WIN32 are defined in 64 bit mode as well. */ # define PLAT_amd64_win64 1 #elif defined(__linux__) && defined(__i386__) # define PLAT_x86_linux 1 #elif defined(__linux__) && defined(__x86_64__) && !defined(__ILP32__) # define PLAT_amd64_linux 1 #elif defined(__linux__) && defined(__powerpc__) && !defined(__powerpc64__) # define PLAT_ppc32_linux 1 #elif defined(__linux__) && defined(__powerpc__) && defined(__powerpc64__) && _CALL_ELF != 2 /* Big Endian uses ELF version 1 */ # define PLAT_ppc64be_linux 1 #elif defined(__linux__) && defined(__powerpc__) && defined(__powerpc64__) && _CALL_ELF == 2 /* Little Endian uses ELF version 2 */ # define PLAT_ppc64le_linux 1 #elif defined(__linux__) && defined(__arm__) && !defined(__aarch64__) # define PLAT_arm_linux 1 #elif defined(__linux__) && defined(__aarch64__) && !defined(__arm__) # define PLAT_arm64_linux 1 #elif defined(__linux__) && defined(__s390__) && defined(__s390x__) # define PLAT_s390x_linux 1 #elif defined(__linux__) && defined(__mips__) && (__mips==64) # define PLAT_mips64_linux 1 #elif defined(__linux__) && defined(__mips__) && (__mips==32) # define PLAT_mips32_linux 1 #elif defined(__linux__) && defined(__nanomips__) # define PLAT_nanomips_linux 1 #elif defined(__sun) && defined(__i386__) # define PLAT_x86_solaris 1 #elif defined(__sun) && defined(__x86_64__) # define PLAT_amd64_solaris 1 #else /* If we're not compiling for our target platform, don't generate any inline asms. */ # if !defined(NVALGRIND) # define NVALGRIND 1 # endif #endif /* ------------------------------------------------------------------ */ /* ARCHITECTURE SPECIFICS for SPECIAL INSTRUCTIONS. There is nothing */ /* in here of use to end-users -- skip to the next section. */ /* ------------------------------------------------------------------ */ /* * VALGRIND_DO_CLIENT_REQUEST(): a statement that invokes a Valgrind client * request. Accepts both pointers and integers as arguments. * * VALGRIND_DO_CLIENT_REQUEST_STMT(): a statement that invokes a Valgrind * client request that does not return a value. * VALGRIND_DO_CLIENT_REQUEST_EXPR(): a C expression that invokes a Valgrind * client request and whose value equals the client request result. Accepts * both pointers and integers as arguments. Note that such calls are not * necessarily pure functions -- they may have side effects. */ #define VALGRIND_DO_CLIENT_REQUEST(_zzq_rlval, _zzq_default, \ _zzq_request, _zzq_arg1, _zzq_arg2, \ _zzq_arg3, _zzq_arg4, _zzq_arg5) \ do { (_zzq_rlval) = VALGRIND_DO_CLIENT_REQUEST_EXPR((_zzq_default), \ (_zzq_request), (_zzq_arg1), (_zzq_arg2), \ (_zzq_arg3), (_zzq_arg4), (_zzq_arg5)); } while (0) #define VALGRIND_DO_CLIENT_REQUEST_STMT(_zzq_request, _zzq_arg1, \ _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ do { (void) VALGRIND_DO_CLIENT_REQUEST_EXPR(0, \ (_zzq_request), (_zzq_arg1), (_zzq_arg2), \ (_zzq_arg3), (_zzq_arg4), (_zzq_arg5)); } while (0) #if defined(NVALGRIND) /* Define NVALGRIND to completely remove the Valgrind magic sequence from the compiled code (analogous to NDEBUG's effects on assert()) */ #define VALGRIND_DO_CLIENT_REQUEST_EXPR( \ _zzq_default, _zzq_request, \ _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ (_zzq_default) #else /* ! NVALGRIND */ /* The following defines the magic code sequences which the JITter spots and handles magically. Don't look too closely at them as they will rot your brain. The assembly code sequences for all architectures is in this one file. This is because this file must be stand-alone, and we don't want to have multiple files. For VALGRIND_DO_CLIENT_REQUEST, we must ensure that the default value gets put in the return slot, so that everything works when this is executed not under Valgrind. Args are passed in a memory block, and so there's no intrinsic limit to the number that could be passed, but it's currently five. The macro args are: _zzq_rlval result lvalue _zzq_default default value (result returned when running on real CPU) _zzq_request request code _zzq_arg1..5 request params The other two macros are used to support function wrapping, and are a lot simpler. VALGRIND_GET_NR_CONTEXT returns the value of the guest's NRADDR pseudo-register and whatever other information is needed to safely run the call original from the wrapper: on ppc64-linux, the R2 value at the divert point is also needed. This information is abstracted into a user-visible type, OrigFn. VALGRIND_CALL_NOREDIR_* behaves the same as the following on the guest, but guarantees that the branch instruction will not be redirected: x86: call *%eax, amd64: call *%rax, ppc32/ppc64: branch-and-link-to-r11. VALGRIND_CALL_NOREDIR is just text, not a complete inline asm, since it needs to be combined with more magic inline asm stuff to be useful. */ /* ----------------- x86-{linux,darwin,solaris} ---------------- */ #if defined(PLAT_x86_linux) || defined(PLAT_x86_darwin) \ || (defined(PLAT_x86_win32) && defined(__GNUC__)) \ || defined(PLAT_x86_solaris) typedef struct { unsigned int nraddr; /* where's the code? */ } OrigFn; #define __SPECIAL_INSTRUCTION_PREAMBLE \ "roll $3, %%edi ; roll $13, %%edi\n\t" \ "roll $29, %%edi ; roll $19, %%edi\n\t" #define VALGRIND_DO_CLIENT_REQUEST_EXPR( \ _zzq_default, _zzq_request, \ _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ __extension__ \ ({volatile unsigned int _zzq_args[6]; \ volatile unsigned int _zzq_result; \ _zzq_args[0] = (unsigned int)(_zzq_request); \ _zzq_args[1] = (unsigned int)(_zzq_arg1); \ _zzq_args[2] = (unsigned int)(_zzq_arg2); \ _zzq_args[3] = (unsigned int)(_zzq_arg3); \ _zzq_args[4] = (unsigned int)(_zzq_arg4); \ _zzq_args[5] = (unsigned int)(_zzq_arg5); \ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ /* %EDX = client_request ( %EAX ) */ \ "xchgl %%ebx,%%ebx" \ : "=d" (_zzq_result) \ : "a" (&_zzq_args[0]), "0" (_zzq_default) \ : "cc", "memory" \ ); \ _zzq_result; \ }) #define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \ { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \ volatile unsigned int __addr; \ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ /* %EAX = guest_NRADDR */ \ "xchgl %%ecx,%%ecx" \ : "=a" (__addr) \ : \ : "cc", "memory" \ ); \ _zzq_orig->nraddr = __addr; \ } #define VALGRIND_CALL_NOREDIR_EAX \ __SPECIAL_INSTRUCTION_PREAMBLE \ /* call-noredir *%EAX */ \ "xchgl %%edx,%%edx\n\t" #define VALGRIND_VEX_INJECT_IR() \ do { \ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ "xchgl %%edi,%%edi\n\t" \ : : : "cc", "memory" \ ); \ } while (0) #endif /* PLAT_x86_linux || PLAT_x86_darwin || (PLAT_x86_win32 && __GNUC__) || PLAT_x86_solaris */ /* ------------------------- x86-Win32 ------------------------- */ #if defined(PLAT_x86_win32) && !defined(__GNUC__) typedef struct { unsigned int nraddr; /* where's the code? */ } OrigFn; #if defined(_MSC_VER) #define __SPECIAL_INSTRUCTION_PREAMBLE \ __asm rol edi, 3 __asm rol edi, 13 \ __asm rol edi, 29 __asm rol edi, 19 #define VALGRIND_DO_CLIENT_REQUEST_EXPR( \ _zzq_default, _zzq_request, \ _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ valgrind_do_client_request_expr((uintptr_t)(_zzq_default), \ (uintptr_t)(_zzq_request), (uintptr_t)(_zzq_arg1), \ (uintptr_t)(_zzq_arg2), (uintptr_t)(_zzq_arg3), \ (uintptr_t)(_zzq_arg4), (uintptr_t)(_zzq_arg5)) static __inline uintptr_t valgrind_do_client_request_expr(uintptr_t _zzq_default, uintptr_t _zzq_request, uintptr_t _zzq_arg1, uintptr_t _zzq_arg2, uintptr_t _zzq_arg3, uintptr_t _zzq_arg4, uintptr_t _zzq_arg5) { volatile uintptr_t _zzq_args[6]; volatile unsigned int _zzq_result; _zzq_args[0] = (uintptr_t)(_zzq_request); _zzq_args[1] = (uintptr_t)(_zzq_arg1); _zzq_args[2] = (uintptr_t)(_zzq_arg2); _zzq_args[3] = (uintptr_t)(_zzq_arg3); _zzq_args[4] = (uintptr_t)(_zzq_arg4); _zzq_args[5] = (uintptr_t)(_zzq_arg5); __asm { __asm lea eax, _zzq_args __asm mov edx, _zzq_default __SPECIAL_INSTRUCTION_PREAMBLE /* %EDX = client_request ( %EAX ) */ __asm xchg ebx,ebx __asm mov _zzq_result, edx } return _zzq_result; } #define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \ { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \ volatile unsigned int __addr; \ __asm { __SPECIAL_INSTRUCTION_PREAMBLE \ /* %EAX = guest_NRADDR */ \ __asm xchg ecx,ecx \ __asm mov __addr, eax \ } \ _zzq_orig->nraddr = __addr; \ } #define VALGRIND_CALL_NOREDIR_EAX ERROR #define VALGRIND_VEX_INJECT_IR() \ do { \ __asm { __SPECIAL_INSTRUCTION_PREAMBLE \ __asm xchg edi,edi \ } \ } while (0) #else #error Unsupported compiler. #endif #endif /* PLAT_x86_win32 */ /* ----------------- amd64-{linux,darwin,solaris} --------------- */ #if defined(PLAT_amd64_linux) || defined(PLAT_amd64_darwin) \ || defined(PLAT_amd64_solaris) \ || (defined(PLAT_amd64_win64) && defined(__GNUC__)) typedef struct { unsigned long int nraddr; /* where's the code? */ } OrigFn; #define __SPECIAL_INSTRUCTION_PREAMBLE \ "rolq $3, %%rdi ; rolq $13, %%rdi\n\t" \ "rolq $61, %%rdi ; rolq $51, %%rdi\n\t" #define VALGRIND_DO_CLIENT_REQUEST_EXPR( \ _zzq_default, _zzq_request, \ _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ __extension__ \ ({ volatile unsigned long int _zzq_args[6]; \ volatile unsigned long int _zzq_result; \ _zzq_args[0] = (unsigned long int)(_zzq_request); \ _zzq_args[1] = (unsigned long int)(_zzq_arg1); \ _zzq_args[2] = (unsigned long int)(_zzq_arg2); \ _zzq_args[3] = (unsigned long int)(_zzq_arg3); \ _zzq_args[4] = (unsigned long int)(_zzq_arg4); \ _zzq_args[5] = (unsigned long int)(_zzq_arg5); \ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ /* %RDX = client_request ( %RAX ) */ \ "xchgq %%rbx,%%rbx" \ : "=d" (_zzq_result) \ : "a" (&_zzq_args[0]), "0" (_zzq_default) \ : "cc", "memory" \ ); \ _zzq_result; \ }) #define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \ { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \ volatile unsigned long int __addr; \ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ /* %RAX = guest_NRADDR */ \ "xchgq %%rcx,%%rcx" \ : "=a" (__addr) \ : \ : "cc", "memory" \ ); \ _zzq_orig->nraddr = __addr; \ } #define VALGRIND_CALL_NOREDIR_RAX \ __SPECIAL_INSTRUCTION_PREAMBLE \ /* call-noredir *%RAX */ \ "xchgq %%rdx,%%rdx\n\t" #define VALGRIND_VEX_INJECT_IR() \ do { \ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ "xchgq %%rdi,%%rdi\n\t" \ : : : "cc", "memory" \ ); \ } while (0) #endif /* PLAT_amd64_linux || PLAT_amd64_darwin || PLAT_amd64_solaris */ /* ------------------------- amd64-Win64 ------------------------- */ #if defined(PLAT_amd64_win64) && !defined(__GNUC__) #error Unsupported compiler. #endif /* PLAT_amd64_win64 */ /* ------------------------ ppc32-linux ------------------------ */ #if defined(PLAT_ppc32_linux) typedef struct { unsigned int nraddr; /* where's the code? */ } OrigFn; #define __SPECIAL_INSTRUCTION_PREAMBLE \ "rlwinm 0,0,3,0,31 ; rlwinm 0,0,13,0,31\n\t" \ "rlwinm 0,0,29,0,31 ; rlwinm 0,0,19,0,31\n\t" #define VALGRIND_DO_CLIENT_REQUEST_EXPR( \ _zzq_default, _zzq_request, \ _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ \ __extension__ \ ({ unsigned int _zzq_args[6]; \ unsigned int _zzq_result; \ unsigned int* _zzq_ptr; \ _zzq_args[0] = (unsigned int)(_zzq_request); \ _zzq_args[1] = (unsigned int)(_zzq_arg1); \ _zzq_args[2] = (unsigned int)(_zzq_arg2); \ _zzq_args[3] = (unsigned int)(_zzq_arg3); \ _zzq_args[4] = (unsigned int)(_zzq_arg4); \ _zzq_args[5] = (unsigned int)(_zzq_arg5); \ _zzq_ptr = _zzq_args; \ __asm__ volatile("mr 3,%1\n\t" /*default*/ \ "mr 4,%2\n\t" /*ptr*/ \ __SPECIAL_INSTRUCTION_PREAMBLE \ /* %R3 = client_request ( %R4 ) */ \ "or 1,1,1\n\t" \ "mr %0,3" /*result*/ \ : "=b" (_zzq_result) \ : "b" (_zzq_default), "b" (_zzq_ptr) \ : "cc", "memory", "r3", "r4"); \ _zzq_result; \ }) #define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \ { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \ unsigned int __addr; \ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ /* %R3 = guest_NRADDR */ \ "or 2,2,2\n\t" \ "mr %0,3" \ : "=b" (__addr) \ : \ : "cc", "memory", "r3" \ ); \ _zzq_orig->nraddr = __addr; \ } #define VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ __SPECIAL_INSTRUCTION_PREAMBLE \ /* branch-and-link-to-noredir *%R11 */ \ "or 3,3,3\n\t" #define VALGRIND_VEX_INJECT_IR() \ do { \ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ "or 5,5,5\n\t" \ ); \ } while (0) #endif /* PLAT_ppc32_linux */ /* ------------------------ ppc64-linux ------------------------ */ #if defined(PLAT_ppc64be_linux) typedef struct { unsigned long int nraddr; /* where's the code? */ unsigned long int r2; /* what tocptr do we need? */ } OrigFn; #define __SPECIAL_INSTRUCTION_PREAMBLE \ "rotldi 0,0,3 ; rotldi 0,0,13\n\t" \ "rotldi 0,0,61 ; rotldi 0,0,51\n\t" #define VALGRIND_DO_CLIENT_REQUEST_EXPR( \ _zzq_default, _zzq_request, \ _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ \ __extension__ \ ({ unsigned long int _zzq_args[6]; \ unsigned long int _zzq_result; \ unsigned long int* _zzq_ptr; \ _zzq_args[0] = (unsigned long int)(_zzq_request); \ _zzq_args[1] = (unsigned long int)(_zzq_arg1); \ _zzq_args[2] = (unsigned long int)(_zzq_arg2); \ _zzq_args[3] = (unsigned long int)(_zzq_arg3); \ _zzq_args[4] = (unsigned long int)(_zzq_arg4); \ _zzq_args[5] = (unsigned long int)(_zzq_arg5); \ _zzq_ptr = _zzq_args; \ __asm__ volatile("mr 3,%1\n\t" /*default*/ \ "mr 4,%2\n\t" /*ptr*/ \ __SPECIAL_INSTRUCTION_PREAMBLE \ /* %R3 = client_request ( %R4 ) */ \ "or 1,1,1\n\t" \ "mr %0,3" /*result*/ \ : "=b" (_zzq_result) \ : "b" (_zzq_default), "b" (_zzq_ptr) \ : "cc", "memory", "r3", "r4"); \ _zzq_result; \ }) #define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \ { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \ unsigned long int __addr; \ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ /* %R3 = guest_NRADDR */ \ "or 2,2,2\n\t" \ "mr %0,3" \ : "=b" (__addr) \ : \ : "cc", "memory", "r3" \ ); \ _zzq_orig->nraddr = __addr; \ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ /* %R3 = guest_NRADDR_GPR2 */ \ "or 4,4,4\n\t" \ "mr %0,3" \ : "=b" (__addr) \ : \ : "cc", "memory", "r3" \ ); \ _zzq_orig->r2 = __addr; \ } #define VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ __SPECIAL_INSTRUCTION_PREAMBLE \ /* branch-and-link-to-noredir *%R11 */ \ "or 3,3,3\n\t" #define VALGRIND_VEX_INJECT_IR() \ do { \ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ "or 5,5,5\n\t" \ ); \ } while (0) #endif /* PLAT_ppc64be_linux */ #if defined(PLAT_ppc64le_linux) typedef struct { unsigned long int nraddr; /* where's the code? */ unsigned long int r2; /* what tocptr do we need? */ } OrigFn; #define __SPECIAL_INSTRUCTION_PREAMBLE \ "rotldi 0,0,3 ; rotldi 0,0,13\n\t" \ "rotldi 0,0,61 ; rotldi 0,0,51\n\t" #define VALGRIND_DO_CLIENT_REQUEST_EXPR( \ _zzq_default, _zzq_request, \ _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ \ __extension__ \ ({ unsigned long int _zzq_args[6]; \ unsigned long int _zzq_result; \ unsigned long int* _zzq_ptr; \ _zzq_args[0] = (unsigned long int)(_zzq_request); \ _zzq_args[1] = (unsigned long int)(_zzq_arg1); \ _zzq_args[2] = (unsigned long int)(_zzq_arg2); \ _zzq_args[3] = (unsigned long int)(_zzq_arg3); \ _zzq_args[4] = (unsigned long int)(_zzq_arg4); \ _zzq_args[5] = (unsigned long int)(_zzq_arg5); \ _zzq_ptr = _zzq_args; \ __asm__ volatile("mr 3,%1\n\t" /*default*/ \ "mr 4,%2\n\t" /*ptr*/ \ __SPECIAL_INSTRUCTION_PREAMBLE \ /* %R3 = client_request ( %R4 ) */ \ "or 1,1,1\n\t" \ "mr %0,3" /*result*/ \ : "=b" (_zzq_result) \ : "b" (_zzq_default), "b" (_zzq_ptr) \ : "cc", "memory", "r3", "r4"); \ _zzq_result; \ }) #define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \ { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \ unsigned long int __addr; \ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ /* %R3 = guest_NRADDR */ \ "or 2,2,2\n\t" \ "mr %0,3" \ : "=b" (__addr) \ : \ : "cc", "memory", "r3" \ ); \ _zzq_orig->nraddr = __addr; \ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ /* %R3 = guest_NRADDR_GPR2 */ \ "or 4,4,4\n\t" \ "mr %0,3" \ : "=b" (__addr) \ : \ : "cc", "memory", "r3" \ ); \ _zzq_orig->r2 = __addr; \ } #define VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R12 \ __SPECIAL_INSTRUCTION_PREAMBLE \ /* branch-and-link-to-noredir *%R12 */ \ "or 3,3,3\n\t" #define VALGRIND_VEX_INJECT_IR() \ do { \ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ "or 5,5,5\n\t" \ ); \ } while (0) #endif /* PLAT_ppc64le_linux */ /* ------------------------- arm-linux ------------------------- */ #if defined(PLAT_arm_linux) typedef struct { unsigned int nraddr; /* where's the code? */ } OrigFn; #define __SPECIAL_INSTRUCTION_PREAMBLE \ "mov r12, r12, ror #3 ; mov r12, r12, ror #13 \n\t" \ "mov r12, r12, ror #29 ; mov r12, r12, ror #19 \n\t" #define VALGRIND_DO_CLIENT_REQUEST_EXPR( \ _zzq_default, _zzq_request, \ _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ \ __extension__ \ ({volatile unsigned int _zzq_args[6]; \ volatile unsigned int _zzq_result; \ _zzq_args[0] = (unsigned int)(_zzq_request); \ _zzq_args[1] = (unsigned int)(_zzq_arg1); \ _zzq_args[2] = (unsigned int)(_zzq_arg2); \ _zzq_args[3] = (unsigned int)(_zzq_arg3); \ _zzq_args[4] = (unsigned int)(_zzq_arg4); \ _zzq_args[5] = (unsigned int)(_zzq_arg5); \ __asm__ volatile("mov r3, %1\n\t" /*default*/ \ "mov r4, %2\n\t" /*ptr*/ \ __SPECIAL_INSTRUCTION_PREAMBLE \ /* R3 = client_request ( R4 ) */ \ "orr r10, r10, r10\n\t" \ "mov %0, r3" /*result*/ \ : "=r" (_zzq_result) \ : "r" (_zzq_default), "r" (&_zzq_args[0]) \ : "cc","memory", "r3", "r4"); \ _zzq_result; \ }) #define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \ { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \ unsigned int __addr; \ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ /* R3 = guest_NRADDR */ \ "orr r11, r11, r11\n\t" \ "mov %0, r3" \ : "=r" (__addr) \ : \ : "cc", "memory", "r3" \ ); \ _zzq_orig->nraddr = __addr; \ } #define VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ __SPECIAL_INSTRUCTION_PREAMBLE \ /* branch-and-link-to-noredir *%R4 */ \ "orr r12, r12, r12\n\t" #define VALGRIND_VEX_INJECT_IR() \ do { \ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ "orr r9, r9, r9\n\t" \ : : : "cc", "memory" \ ); \ } while (0) #endif /* PLAT_arm_linux */ /* ------------------------ arm64-linux ------------------------- */ #if defined(PLAT_arm64_linux) typedef struct { unsigned long int nraddr; /* where's the code? */ } OrigFn; #define __SPECIAL_INSTRUCTION_PREAMBLE \ "ror x12, x12, #3 ; ror x12, x12, #13 \n\t" \ "ror x12, x12, #51 ; ror x12, x12, #61 \n\t" #define VALGRIND_DO_CLIENT_REQUEST_EXPR( \ _zzq_default, _zzq_request, \ _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ \ __extension__ \ ({volatile unsigned long int _zzq_args[6]; \ volatile unsigned long int _zzq_result; \ _zzq_args[0] = (unsigned long int)(_zzq_request); \ _zzq_args[1] = (unsigned long int)(_zzq_arg1); \ _zzq_args[2] = (unsigned long int)(_zzq_arg2); \ _zzq_args[3] = (unsigned long int)(_zzq_arg3); \ _zzq_args[4] = (unsigned long int)(_zzq_arg4); \ _zzq_args[5] = (unsigned long int)(_zzq_arg5); \ __asm__ volatile("mov x3, %1\n\t" /*default*/ \ "mov x4, %2\n\t" /*ptr*/ \ __SPECIAL_INSTRUCTION_PREAMBLE \ /* X3 = client_request ( X4 ) */ \ "orr x10, x10, x10\n\t" \ "mov %0, x3" /*result*/ \ : "=r" (_zzq_result) \ : "r" ((unsigned long int)(_zzq_default)), \ "r" (&_zzq_args[0]) \ : "cc","memory", "x3", "x4"); \ _zzq_result; \ }) #define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \ { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \ unsigned long int __addr; \ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ /* X3 = guest_NRADDR */ \ "orr x11, x11, x11\n\t" \ "mov %0, x3" \ : "=r" (__addr) \ : \ : "cc", "memory", "x3" \ ); \ _zzq_orig->nraddr = __addr; \ } #define VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_X8 \ __SPECIAL_INSTRUCTION_PREAMBLE \ /* branch-and-link-to-noredir X8 */ \ "orr x12, x12, x12\n\t" #define VALGRIND_VEX_INJECT_IR() \ do { \ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ "orr x9, x9, x9\n\t" \ : : : "cc", "memory" \ ); \ } while (0) #endif /* PLAT_arm64_linux */ /* ------------------------ s390x-linux ------------------------ */ #if defined(PLAT_s390x_linux) typedef struct { unsigned long int nraddr; /* where's the code? */ } OrigFn; /* __SPECIAL_INSTRUCTION_PREAMBLE will be used to identify Valgrind specific * code. This detection is implemented in platform specific toIR.c * (e.g. VEX/priv/guest_s390_decoder.c). */ #define __SPECIAL_INSTRUCTION_PREAMBLE \ "lr 15,15\n\t" \ "lr 1,1\n\t" \ "lr 2,2\n\t" \ "lr 3,3\n\t" #define __CLIENT_REQUEST_CODE "lr 2,2\n\t" #define __GET_NR_CONTEXT_CODE "lr 3,3\n\t" #define __CALL_NO_REDIR_CODE "lr 4,4\n\t" #define __VEX_INJECT_IR_CODE "lr 5,5\n\t" #define VALGRIND_DO_CLIENT_REQUEST_EXPR( \ _zzq_default, _zzq_request, \ _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ __extension__ \ ({volatile unsigned long int _zzq_args[6]; \ volatile unsigned long int _zzq_result; \ _zzq_args[0] = (unsigned long int)(_zzq_request); \ _zzq_args[1] = (unsigned long int)(_zzq_arg1); \ _zzq_args[2] = (unsigned long int)(_zzq_arg2); \ _zzq_args[3] = (unsigned long int)(_zzq_arg3); \ _zzq_args[4] = (unsigned long int)(_zzq_arg4); \ _zzq_args[5] = (unsigned long int)(_zzq_arg5); \ __asm__ volatile(/* r2 = args */ \ "lgr 2,%1\n\t" \ /* r3 = default */ \ "lgr 3,%2\n\t" \ __SPECIAL_INSTRUCTION_PREAMBLE \ __CLIENT_REQUEST_CODE \ /* results = r3 */ \ "lgr %0, 3\n\t" \ : "=d" (_zzq_result) \ : "a" (&_zzq_args[0]), "0" (_zzq_default) \ : "cc", "2", "3", "memory" \ ); \ _zzq_result; \ }) #define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \ { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \ volatile unsigned long int __addr; \ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ __GET_NR_CONTEXT_CODE \ "lgr %0, 3\n\t" \ : "=a" (__addr) \ : \ : "cc", "3", "memory" \ ); \ _zzq_orig->nraddr = __addr; \ } #define VALGRIND_CALL_NOREDIR_R1 \ __SPECIAL_INSTRUCTION_PREAMBLE \ __CALL_NO_REDIR_CODE #define VALGRIND_VEX_INJECT_IR() \ do { \ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ __VEX_INJECT_IR_CODE); \ } while (0) #endif /* PLAT_s390x_linux */ /* ------------------------- mips32-linux ---------------- */ #if defined(PLAT_mips32_linux) typedef struct { unsigned int nraddr; /* where's the code? */ } OrigFn; /* .word 0x342 * .word 0x742 * .word 0xC2 * .word 0x4C2*/ #define __SPECIAL_INSTRUCTION_PREAMBLE \ "srl $0, $0, 13\n\t" \ "srl $0, $0, 29\n\t" \ "srl $0, $0, 3\n\t" \ "srl $0, $0, 19\n\t" #define VALGRIND_DO_CLIENT_REQUEST_EXPR( \ _zzq_default, _zzq_request, \ _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ __extension__ \ ({ volatile unsigned int _zzq_args[6]; \ volatile unsigned int _zzq_result; \ _zzq_args[0] = (unsigned int)(_zzq_request); \ _zzq_args[1] = (unsigned int)(_zzq_arg1); \ _zzq_args[2] = (unsigned int)(_zzq_arg2); \ _zzq_args[3] = (unsigned int)(_zzq_arg3); \ _zzq_args[4] = (unsigned int)(_zzq_arg4); \ _zzq_args[5] = (unsigned int)(_zzq_arg5); \ __asm__ volatile("move $11, %1\n\t" /*default*/ \ "move $12, %2\n\t" /*ptr*/ \ __SPECIAL_INSTRUCTION_PREAMBLE \ /* T3 = client_request ( T4 ) */ \ "or $13, $13, $13\n\t" \ "move %0, $11\n\t" /*result*/ \ : "=r" (_zzq_result) \ : "r" (_zzq_default), "r" (&_zzq_args[0]) \ : "$11", "$12", "memory"); \ _zzq_result; \ }) #define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \ { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \ volatile unsigned int __addr; \ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ /* %t9 = guest_NRADDR */ \ "or $14, $14, $14\n\t" \ "move %0, $11" /*result*/ \ : "=r" (__addr) \ : \ : "$11" \ ); \ _zzq_orig->nraddr = __addr; \ } #define VALGRIND_CALL_NOREDIR_T9 \ __SPECIAL_INSTRUCTION_PREAMBLE \ /* call-noredir *%t9 */ \ "or $15, $15, $15\n\t" #define VALGRIND_VEX_INJECT_IR() \ do { \ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ "or $11, $11, $11\n\t" \ ); \ } while (0) #endif /* PLAT_mips32_linux */ /* ------------------------- mips64-linux ---------------- */ #if defined(PLAT_mips64_linux) typedef struct { unsigned long nraddr; /* where's the code? */ } OrigFn; /* dsll $0,$0, 3 * dsll $0,$0, 13 * dsll $0,$0, 29 * dsll $0,$0, 19*/ #define __SPECIAL_INSTRUCTION_PREAMBLE \ "dsll $0,$0, 3 ; dsll $0,$0,13\n\t" \ "dsll $0,$0,29 ; dsll $0,$0,19\n\t" #define VALGRIND_DO_CLIENT_REQUEST_EXPR( \ _zzq_default, _zzq_request, \ _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ __extension__ \ ({ volatile unsigned long int _zzq_args[6]; \ volatile unsigned long int _zzq_result; \ _zzq_args[0] = (unsigned long int)(_zzq_request); \ _zzq_args[1] = (unsigned long int)(_zzq_arg1); \ _zzq_args[2] = (unsigned long int)(_zzq_arg2); \ _zzq_args[3] = (unsigned long int)(_zzq_arg3); \ _zzq_args[4] = (unsigned long int)(_zzq_arg4); \ _zzq_args[5] = (unsigned long int)(_zzq_arg5); \ __asm__ volatile("move $11, %1\n\t" /*default*/ \ "move $12, %2\n\t" /*ptr*/ \ __SPECIAL_INSTRUCTION_PREAMBLE \ /* $11 = client_request ( $12 ) */ \ "or $13, $13, $13\n\t" \ "move %0, $11\n\t" /*result*/ \ : "=r" (_zzq_result) \ : "r" (_zzq_default), "r" (&_zzq_args[0]) \ : "$11", "$12", "memory"); \ _zzq_result; \ }) #define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \ { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \ volatile unsigned long int __addr; \ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ /* $11 = guest_NRADDR */ \ "or $14, $14, $14\n\t" \ "move %0, $11" /*result*/ \ : "=r" (__addr) \ : \ : "$11"); \ _zzq_orig->nraddr = __addr; \ } #define VALGRIND_CALL_NOREDIR_T9 \ __SPECIAL_INSTRUCTION_PREAMBLE \ /* call-noredir $25 */ \ "or $15, $15, $15\n\t" #define VALGRIND_VEX_INJECT_IR() \ do { \ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ "or $11, $11, $11\n\t" \ ); \ } while (0) #endif /* PLAT_mips64_linux */ #if defined(PLAT_nanomips_linux) typedef struct { unsigned int nraddr; /* where's the code? */ } OrigFn; /* 8000 c04d srl zero, zero, 13 8000 c05d srl zero, zero, 29 8000 c043 srl zero, zero, 3 8000 c053 srl zero, zero, 19 */ #define __SPECIAL_INSTRUCTION_PREAMBLE "srl[32] $zero, $zero, 13 \n\t" \ "srl[32] $zero, $zero, 29 \n\t" \ "srl[32] $zero, $zero, 3 \n\t" \ "srl[32] $zero, $zero, 19 \n\t" #define VALGRIND_DO_CLIENT_REQUEST_EXPR( \ _zzq_default, _zzq_request, \ _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ __extension__ \ ({ volatile unsigned int _zzq_args[6]; \ volatile unsigned int _zzq_result; \ _zzq_args[0] = (unsigned int)(_zzq_request); \ _zzq_args[1] = (unsigned int)(_zzq_arg1); \ _zzq_args[2] = (unsigned int)(_zzq_arg2); \ _zzq_args[3] = (unsigned int)(_zzq_arg3); \ _zzq_args[4] = (unsigned int)(_zzq_arg4); \ _zzq_args[5] = (unsigned int)(_zzq_arg5); \ __asm__ volatile("move $a7, %1\n\t" /* default */ \ "move $t0, %2\n\t" /* ptr */ \ __SPECIAL_INSTRUCTION_PREAMBLE \ /* $a7 = client_request( $t0 ) */ \ "or[32] $t0, $t0, $t0\n\t" \ "move %0, $a7\n\t" /* result */ \ : "=r" (_zzq_result) \ : "r" (_zzq_default), "r" (&_zzq_args[0]) \ : "$a7", "$t0", "memory"); \ _zzq_result; \ }) #define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \ { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \ volatile unsigned long int __addr; \ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ /* $a7 = guest_NRADDR */ \ "or[32] $t1, $t1, $t1\n\t" \ "move %0, $a7" /*result*/ \ : "=r" (__addr) \ : \ : "$a7"); \ _zzq_orig->nraddr = __addr; \ } #define VALGRIND_CALL_NOREDIR_T9 \ __SPECIAL_INSTRUCTION_PREAMBLE \ /* call-noredir $25 */ \ "or[32] $t2, $t2, $t2\n\t" #define VALGRIND_VEX_INJECT_IR() \ do { \ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ "or[32] $t3, $t3, $t3\n\t" \ ); \ } while (0) #endif /* Insert assembly code for other platforms here... */ #endif /* NVALGRIND */ /* ------------------------------------------------------------------ */ /* PLATFORM SPECIFICS for FUNCTION WRAPPING. This is all very */ /* ugly. It's the least-worst tradeoff I can think of. */ /* ------------------------------------------------------------------ */ /* This section defines magic (a.k.a appalling-hack) macros for doing guaranteed-no-redirection macros, so as to get from function wrappers to the functions they are wrapping. The whole point is to construct standard call sequences, but to do the call itself with a special no-redirect call pseudo-instruction that the JIT understands and handles specially. This section is long and repetitious, and I can't see a way to make it shorter. The naming scheme is as follows: CALL_FN_{W,v}_{v,W,WW,WWW,WWWW,5W,6W,7W,etc} 'W' stands for "word" and 'v' for "void". Hence there are different macros for calling arity 0, 1, 2, 3, 4, etc, functions, and for each, the possibility of returning a word-typed result, or no result. */ /* Use these to write the name of your wrapper. NOTE: duplicates VG_WRAP_FUNCTION_Z{U,Z} in pub_tool_redir.h. NOTE also: inserts the default behaviour equivalance class tag "0000" into the name. See pub_tool_redir.h for details -- normally you don't need to think about this, though. */ /* Use an extra level of macroisation so as to ensure the soname/fnname args are fully macro-expanded before pasting them together. */ #define VG_CONCAT4(_aa,_bb,_cc,_dd) _aa##_bb##_cc##_dd #define I_WRAP_SONAME_FNNAME_ZU(soname,fnname) \ VG_CONCAT4(_vgw00000ZU_,soname,_,fnname) #define I_WRAP_SONAME_FNNAME_ZZ(soname,fnname) \ VG_CONCAT4(_vgw00000ZZ_,soname,_,fnname) /* Use this macro from within a wrapper function to collect the context (address and possibly other info) of the original function. Once you have that you can then use it in one of the CALL_FN_ macros. The type of the argument _lval is OrigFn. */ #define VALGRIND_GET_ORIG_FN(_lval) VALGRIND_GET_NR_CONTEXT(_lval) /* Also provide end-user facilities for function replacement, rather than wrapping. A replacement function differs from a wrapper in that it has no way to get hold of the original function being called, and hence no way to call onwards to it. In a replacement function, VALGRIND_GET_ORIG_FN always returns zero. */ #define I_REPLACE_SONAME_FNNAME_ZU(soname,fnname) \ VG_CONCAT4(_vgr00000ZU_,soname,_,fnname) #define I_REPLACE_SONAME_FNNAME_ZZ(soname,fnname) \ VG_CONCAT4(_vgr00000ZZ_,soname,_,fnname) /* Derivatives of the main macros below, for calling functions returning void. */ #define CALL_FN_v_v(fnptr) \ do { volatile unsigned long _junk; \ CALL_FN_W_v(_junk,fnptr); } while (0) #define CALL_FN_v_W(fnptr, arg1) \ do { volatile unsigned long _junk; \ CALL_FN_W_W(_junk,fnptr,arg1); } while (0) #define CALL_FN_v_WW(fnptr, arg1,arg2) \ do { volatile unsigned long _junk; \ CALL_FN_W_WW(_junk,fnptr,arg1,arg2); } while (0) #define CALL_FN_v_WWW(fnptr, arg1,arg2,arg3) \ do { volatile unsigned long _junk; \ CALL_FN_W_WWW(_junk,fnptr,arg1,arg2,arg3); } while (0) #define CALL_FN_v_WWWW(fnptr, arg1,arg2,arg3,arg4) \ do { volatile unsigned long _junk; \ CALL_FN_W_WWWW(_junk,fnptr,arg1,arg2,arg3,arg4); } while (0) #define CALL_FN_v_5W(fnptr, arg1,arg2,arg3,arg4,arg5) \ do { volatile unsigned long _junk; \ CALL_FN_W_5W(_junk,fnptr,arg1,arg2,arg3,arg4,arg5); } while (0) #define CALL_FN_v_6W(fnptr, arg1,arg2,arg3,arg4,arg5,arg6) \ do { volatile unsigned long _junk; \ CALL_FN_W_6W(_junk,fnptr,arg1,arg2,arg3,arg4,arg5,arg6); } while (0) #define CALL_FN_v_7W(fnptr, arg1,arg2,arg3,arg4,arg5,arg6,arg7) \ do { volatile unsigned long _junk; \ CALL_FN_W_7W(_junk,fnptr,arg1,arg2,arg3,arg4,arg5,arg6,arg7); } while (0) /* ----------------- x86-{linux,darwin,solaris} ---------------- */ #if defined(PLAT_x86_linux) || defined(PLAT_x86_darwin) \ || defined(PLAT_x86_solaris) /* These regs are trashed by the hidden call. No need to mention eax as gcc can already see that, plus causes gcc to bomb. */ #define __CALLER_SAVED_REGS /*"eax"*/ "ecx", "edx" /* Macros to save and align the stack before making a function call and restore it afterwards as gcc may not keep the stack pointer aligned if it doesn't realise calls are being made to other functions. */ #define VALGRIND_ALIGN_STACK \ "movl %%esp,%%edi\n\t" \ "andl $0xfffffff0,%%esp\n\t" #define VALGRIND_RESTORE_STACK \ "movl %%edi,%%esp\n\t" /* These CALL_FN_ macros assume that on x86-linux, sizeof(unsigned long) == 4. */ #define CALL_FN_W_v(lval, orig) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[1]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "movl (%%eax), %%eax\n\t" /* target->%eax */ \ VALGRIND_CALL_NOREDIR_EAX \ VALGRIND_RESTORE_STACK \ : /*out*/ "=a" (_res) \ : /*in*/ "a" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "edi" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_W(lval, orig, arg1) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[2]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "subl $12, %%esp\n\t" \ "pushl 4(%%eax)\n\t" \ "movl (%%eax), %%eax\n\t" /* target->%eax */ \ VALGRIND_CALL_NOREDIR_EAX \ VALGRIND_RESTORE_STACK \ : /*out*/ "=a" (_res) \ : /*in*/ "a" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "edi" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WW(lval, orig, arg1,arg2) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "subl $8, %%esp\n\t" \ "pushl 8(%%eax)\n\t" \ "pushl 4(%%eax)\n\t" \ "movl (%%eax), %%eax\n\t" /* target->%eax */ \ VALGRIND_CALL_NOREDIR_EAX \ VALGRIND_RESTORE_STACK \ : /*out*/ "=a" (_res) \ : /*in*/ "a" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "edi" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[4]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "subl $4, %%esp\n\t" \ "pushl 12(%%eax)\n\t" \ "pushl 8(%%eax)\n\t" \ "pushl 4(%%eax)\n\t" \ "movl (%%eax), %%eax\n\t" /* target->%eax */ \ VALGRIND_CALL_NOREDIR_EAX \ VALGRIND_RESTORE_STACK \ : /*out*/ "=a" (_res) \ : /*in*/ "a" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "edi" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[5]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "pushl 16(%%eax)\n\t" \ "pushl 12(%%eax)\n\t" \ "pushl 8(%%eax)\n\t" \ "pushl 4(%%eax)\n\t" \ "movl (%%eax), %%eax\n\t" /* target->%eax */ \ VALGRIND_CALL_NOREDIR_EAX \ VALGRIND_RESTORE_STACK \ : /*out*/ "=a" (_res) \ : /*in*/ "a" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "edi" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[6]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "subl $12, %%esp\n\t" \ "pushl 20(%%eax)\n\t" \ "pushl 16(%%eax)\n\t" \ "pushl 12(%%eax)\n\t" \ "pushl 8(%%eax)\n\t" \ "pushl 4(%%eax)\n\t" \ "movl (%%eax), %%eax\n\t" /* target->%eax */ \ VALGRIND_CALL_NOREDIR_EAX \ VALGRIND_RESTORE_STACK \ : /*out*/ "=a" (_res) \ : /*in*/ "a" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "edi" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[7]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "subl $8, %%esp\n\t" \ "pushl 24(%%eax)\n\t" \ "pushl 20(%%eax)\n\t" \ "pushl 16(%%eax)\n\t" \ "pushl 12(%%eax)\n\t" \ "pushl 8(%%eax)\n\t" \ "pushl 4(%%eax)\n\t" \ "movl (%%eax), %%eax\n\t" /* target->%eax */ \ VALGRIND_CALL_NOREDIR_EAX \ VALGRIND_RESTORE_STACK \ : /*out*/ "=a" (_res) \ : /*in*/ "a" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "edi" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[8]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "subl $4, %%esp\n\t" \ "pushl 28(%%eax)\n\t" \ "pushl 24(%%eax)\n\t" \ "pushl 20(%%eax)\n\t" \ "pushl 16(%%eax)\n\t" \ "pushl 12(%%eax)\n\t" \ "pushl 8(%%eax)\n\t" \ "pushl 4(%%eax)\n\t" \ "movl (%%eax), %%eax\n\t" /* target->%eax */ \ VALGRIND_CALL_NOREDIR_EAX \ VALGRIND_RESTORE_STACK \ : /*out*/ "=a" (_res) \ : /*in*/ "a" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "edi" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[9]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "pushl 32(%%eax)\n\t" \ "pushl 28(%%eax)\n\t" \ "pushl 24(%%eax)\n\t" \ "pushl 20(%%eax)\n\t" \ "pushl 16(%%eax)\n\t" \ "pushl 12(%%eax)\n\t" \ "pushl 8(%%eax)\n\t" \ "pushl 4(%%eax)\n\t" \ "movl (%%eax), %%eax\n\t" /* target->%eax */ \ VALGRIND_CALL_NOREDIR_EAX \ VALGRIND_RESTORE_STACK \ : /*out*/ "=a" (_res) \ : /*in*/ "a" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "edi" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[10]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ _argvec[9] = (unsigned long)(arg9); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "subl $12, %%esp\n\t" \ "pushl 36(%%eax)\n\t" \ "pushl 32(%%eax)\n\t" \ "pushl 28(%%eax)\n\t" \ "pushl 24(%%eax)\n\t" \ "pushl 20(%%eax)\n\t" \ "pushl 16(%%eax)\n\t" \ "pushl 12(%%eax)\n\t" \ "pushl 8(%%eax)\n\t" \ "pushl 4(%%eax)\n\t" \ "movl (%%eax), %%eax\n\t" /* target->%eax */ \ VALGRIND_CALL_NOREDIR_EAX \ VALGRIND_RESTORE_STACK \ : /*out*/ "=a" (_res) \ : /*in*/ "a" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "edi" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9,arg10) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[11]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ _argvec[9] = (unsigned long)(arg9); \ _argvec[10] = (unsigned long)(arg10); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "subl $8, %%esp\n\t" \ "pushl 40(%%eax)\n\t" \ "pushl 36(%%eax)\n\t" \ "pushl 32(%%eax)\n\t" \ "pushl 28(%%eax)\n\t" \ "pushl 24(%%eax)\n\t" \ "pushl 20(%%eax)\n\t" \ "pushl 16(%%eax)\n\t" \ "pushl 12(%%eax)\n\t" \ "pushl 8(%%eax)\n\t" \ "pushl 4(%%eax)\n\t" \ "movl (%%eax), %%eax\n\t" /* target->%eax */ \ VALGRIND_CALL_NOREDIR_EAX \ VALGRIND_RESTORE_STACK \ : /*out*/ "=a" (_res) \ : /*in*/ "a" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "edi" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5, \ arg6,arg7,arg8,arg9,arg10, \ arg11) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[12]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ _argvec[9] = (unsigned long)(arg9); \ _argvec[10] = (unsigned long)(arg10); \ _argvec[11] = (unsigned long)(arg11); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "subl $4, %%esp\n\t" \ "pushl 44(%%eax)\n\t" \ "pushl 40(%%eax)\n\t" \ "pushl 36(%%eax)\n\t" \ "pushl 32(%%eax)\n\t" \ "pushl 28(%%eax)\n\t" \ "pushl 24(%%eax)\n\t" \ "pushl 20(%%eax)\n\t" \ "pushl 16(%%eax)\n\t" \ "pushl 12(%%eax)\n\t" \ "pushl 8(%%eax)\n\t" \ "pushl 4(%%eax)\n\t" \ "movl (%%eax), %%eax\n\t" /* target->%eax */ \ VALGRIND_CALL_NOREDIR_EAX \ VALGRIND_RESTORE_STACK \ : /*out*/ "=a" (_res) \ : /*in*/ "a" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "edi" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5, \ arg6,arg7,arg8,arg9,arg10, \ arg11,arg12) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[13]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ _argvec[9] = (unsigned long)(arg9); \ _argvec[10] = (unsigned long)(arg10); \ _argvec[11] = (unsigned long)(arg11); \ _argvec[12] = (unsigned long)(arg12); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "pushl 48(%%eax)\n\t" \ "pushl 44(%%eax)\n\t" \ "pushl 40(%%eax)\n\t" \ "pushl 36(%%eax)\n\t" \ "pushl 32(%%eax)\n\t" \ "pushl 28(%%eax)\n\t" \ "pushl 24(%%eax)\n\t" \ "pushl 20(%%eax)\n\t" \ "pushl 16(%%eax)\n\t" \ "pushl 12(%%eax)\n\t" \ "pushl 8(%%eax)\n\t" \ "pushl 4(%%eax)\n\t" \ "movl (%%eax), %%eax\n\t" /* target->%eax */ \ VALGRIND_CALL_NOREDIR_EAX \ VALGRIND_RESTORE_STACK \ : /*out*/ "=a" (_res) \ : /*in*/ "a" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "edi" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #endif /* PLAT_x86_linux || PLAT_x86_darwin || PLAT_x86_solaris */ /* ---------------- amd64-{linux,darwin,solaris} --------------- */ #if defined(PLAT_amd64_linux) || defined(PLAT_amd64_darwin) \ || defined(PLAT_amd64_solaris) /* ARGREGS: rdi rsi rdx rcx r8 r9 (the rest on stack in R-to-L order) */ /* These regs are trashed by the hidden call. */ #define __CALLER_SAVED_REGS /*"rax",*/ "rcx", "rdx", "rsi", \ "rdi", "r8", "r9", "r10", "r11" /* This is all pretty complex. It's so as to make stack unwinding work reliably. See bug 243270. The basic problem is the sub and add of 128 of %rsp in all of the following macros. If gcc believes the CFA is in %rsp, then unwinding may fail, because what's at the CFA is not what gcc "expected" when it constructs the CFIs for the places where the macros are instantiated. But we can't just add a CFI annotation to increase the CFA offset by 128, to match the sub of 128 from %rsp, because we don't know whether gcc has chosen %rsp as the CFA at that point, or whether it has chosen some other register (eg, %rbp). In the latter case, adding a CFI annotation to change the CFA offset is simply wrong. So the solution is to get hold of the CFA using __builtin_dwarf_cfa(), put it in a known register, and add a CFI annotation to say what the register is. We choose %rbp for this (perhaps perversely), because: (1) %rbp is already subject to unwinding. If a new register was chosen then the unwinder would have to unwind it in all stack traces, which is expensive, and (2) %rbp is already subject to precise exception updates in the JIT. If a new register was chosen, we'd have to have precise exceptions for it too, which reduces performance of the generated code. However .. one extra complication. We can't just whack the result of __builtin_dwarf_cfa() into %rbp and then add %rbp to the list of trashed registers at the end of the inline assembly fragments; gcc won't allow %rbp to appear in that list. Hence instead we need to stash %rbp in %r15 for the duration of the asm, and say that %r15 is trashed instead. gcc seems happy to go with that. Oh .. and this all needs to be conditionalised so that it is unchanged from before this commit, when compiled with older gccs that don't support __builtin_dwarf_cfa. Furthermore, since this header file is freestanding, it has to be independent of config.h, and so the following conditionalisation cannot depend on configure time checks. Although it's not clear from 'defined(__GNUC__) && defined(__GCC_HAVE_DWARF2_CFI_ASM)', this expression excludes Darwin. .cfi directives in Darwin assembly appear to be completely different and I haven't investigated how they work. For even more entertainment value, note we have to use the completely undocumented __builtin_dwarf_cfa(), which appears to really compute the CFA, whereas __builtin_frame_address(0) claims to but actually doesn't. See https://bugs.kde.org/show_bug.cgi?id=243270#c47 */ #if defined(__GNUC__) && defined(__GCC_HAVE_DWARF2_CFI_ASM) # define __FRAME_POINTER \ ,"r"(__builtin_dwarf_cfa()) # define VALGRIND_CFI_PROLOGUE \ "movq %%rbp, %%r15\n\t" \ "movq %2, %%rbp\n\t" \ ".cfi_remember_state\n\t" \ ".cfi_def_cfa rbp, 0\n\t" # define VALGRIND_CFI_EPILOGUE \ "movq %%r15, %%rbp\n\t" \ ".cfi_restore_state\n\t" #else # define __FRAME_POINTER # define VALGRIND_CFI_PROLOGUE # define VALGRIND_CFI_EPILOGUE #endif /* Macros to save and align the stack before making a function call and restore it afterwards as gcc may not keep the stack pointer aligned if it doesn't realise calls are being made to other functions. */ #define VALGRIND_ALIGN_STACK \ "movq %%rsp,%%r14\n\t" \ "andq $0xfffffffffffffff0,%%rsp\n\t" #define VALGRIND_RESTORE_STACK \ "movq %%r14,%%rsp\n\t" /* These CALL_FN_ macros assume that on amd64-linux, sizeof(unsigned long) == 8. */ /* NB 9 Sept 07. There is a nasty kludge here in all these CALL_FN_ macros. In order not to trash the stack redzone, we need to drop %rsp by 128 before the hidden call, and restore afterwards. The nastyness is that it is only by luck that the stack still appears to be unwindable during the hidden call - since then the behaviour of any routine using this macro does not match what the CFI data says. Sigh. Why is this important? Imagine that a wrapper has a stack allocated local, and passes to the hidden call, a pointer to it. Because gcc does not know about the hidden call, it may allocate that local in the redzone. Unfortunately the hidden call may then trash it before it comes to use it. So we must step clear of the redzone, for the duration of the hidden call, to make it safe. Probably the same problem afflicts the other redzone-style ABIs too (ppc64-linux); but for those, the stack is self describing (none of this CFI nonsense) so at least messing with the stack pointer doesn't give a danger of non-unwindable stack. */ #define CALL_FN_W_v(lval, orig) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[1]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ __asm__ volatile( \ VALGRIND_CFI_PROLOGUE \ VALGRIND_ALIGN_STACK \ "subq $128,%%rsp\n\t" \ "movq (%%rax), %%rax\n\t" /* target->%rax */ \ VALGRIND_CALL_NOREDIR_RAX \ VALGRIND_RESTORE_STACK \ VALGRIND_CFI_EPILOGUE \ : /*out*/ "=a" (_res) \ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r14", "r15" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_W(lval, orig, arg1) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[2]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ __asm__ volatile( \ VALGRIND_CFI_PROLOGUE \ VALGRIND_ALIGN_STACK \ "subq $128,%%rsp\n\t" \ "movq 8(%%rax), %%rdi\n\t" \ "movq (%%rax), %%rax\n\t" /* target->%rax */ \ VALGRIND_CALL_NOREDIR_RAX \ VALGRIND_RESTORE_STACK \ VALGRIND_CFI_EPILOGUE \ : /*out*/ "=a" (_res) \ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r14", "r15" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WW(lval, orig, arg1,arg2) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ __asm__ volatile( \ VALGRIND_CFI_PROLOGUE \ VALGRIND_ALIGN_STACK \ "subq $128,%%rsp\n\t" \ "movq 16(%%rax), %%rsi\n\t" \ "movq 8(%%rax), %%rdi\n\t" \ "movq (%%rax), %%rax\n\t" /* target->%rax */ \ VALGRIND_CALL_NOREDIR_RAX \ VALGRIND_RESTORE_STACK \ VALGRIND_CFI_EPILOGUE \ : /*out*/ "=a" (_res) \ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r14", "r15" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[4]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ __asm__ volatile( \ VALGRIND_CFI_PROLOGUE \ VALGRIND_ALIGN_STACK \ "subq $128,%%rsp\n\t" \ "movq 24(%%rax), %%rdx\n\t" \ "movq 16(%%rax), %%rsi\n\t" \ "movq 8(%%rax), %%rdi\n\t" \ "movq (%%rax), %%rax\n\t" /* target->%rax */ \ VALGRIND_CALL_NOREDIR_RAX \ VALGRIND_RESTORE_STACK \ VALGRIND_CFI_EPILOGUE \ : /*out*/ "=a" (_res) \ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r14", "r15" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[5]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ __asm__ volatile( \ VALGRIND_CFI_PROLOGUE \ VALGRIND_ALIGN_STACK \ "subq $128,%%rsp\n\t" \ "movq 32(%%rax), %%rcx\n\t" \ "movq 24(%%rax), %%rdx\n\t" \ "movq 16(%%rax), %%rsi\n\t" \ "movq 8(%%rax), %%rdi\n\t" \ "movq (%%rax), %%rax\n\t" /* target->%rax */ \ VALGRIND_CALL_NOREDIR_RAX \ VALGRIND_RESTORE_STACK \ VALGRIND_CFI_EPILOGUE \ : /*out*/ "=a" (_res) \ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r14", "r15" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[6]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ __asm__ volatile( \ VALGRIND_CFI_PROLOGUE \ VALGRIND_ALIGN_STACK \ "subq $128,%%rsp\n\t" \ "movq 40(%%rax), %%r8\n\t" \ "movq 32(%%rax), %%rcx\n\t" \ "movq 24(%%rax), %%rdx\n\t" \ "movq 16(%%rax), %%rsi\n\t" \ "movq 8(%%rax), %%rdi\n\t" \ "movq (%%rax), %%rax\n\t" /* target->%rax */ \ VALGRIND_CALL_NOREDIR_RAX \ VALGRIND_RESTORE_STACK \ VALGRIND_CFI_EPILOGUE \ : /*out*/ "=a" (_res) \ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r14", "r15" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[7]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ __asm__ volatile( \ VALGRIND_CFI_PROLOGUE \ VALGRIND_ALIGN_STACK \ "subq $128,%%rsp\n\t" \ "movq 48(%%rax), %%r9\n\t" \ "movq 40(%%rax), %%r8\n\t" \ "movq 32(%%rax), %%rcx\n\t" \ "movq 24(%%rax), %%rdx\n\t" \ "movq 16(%%rax), %%rsi\n\t" \ "movq 8(%%rax), %%rdi\n\t" \ "movq (%%rax), %%rax\n\t" /* target->%rax */ \ VALGRIND_CALL_NOREDIR_RAX \ VALGRIND_RESTORE_STACK \ VALGRIND_CFI_EPILOGUE \ : /*out*/ "=a" (_res) \ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r14", "r15" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[8]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ __asm__ volatile( \ VALGRIND_CFI_PROLOGUE \ VALGRIND_ALIGN_STACK \ "subq $136,%%rsp\n\t" \ "pushq 56(%%rax)\n\t" \ "movq 48(%%rax), %%r9\n\t" \ "movq 40(%%rax), %%r8\n\t" \ "movq 32(%%rax), %%rcx\n\t" \ "movq 24(%%rax), %%rdx\n\t" \ "movq 16(%%rax), %%rsi\n\t" \ "movq 8(%%rax), %%rdi\n\t" \ "movq (%%rax), %%rax\n\t" /* target->%rax */ \ VALGRIND_CALL_NOREDIR_RAX \ VALGRIND_RESTORE_STACK \ VALGRIND_CFI_EPILOGUE \ : /*out*/ "=a" (_res) \ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r14", "r15" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[9]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ __asm__ volatile( \ VALGRIND_CFI_PROLOGUE \ VALGRIND_ALIGN_STACK \ "subq $128,%%rsp\n\t" \ "pushq 64(%%rax)\n\t" \ "pushq 56(%%rax)\n\t" \ "movq 48(%%rax), %%r9\n\t" \ "movq 40(%%rax), %%r8\n\t" \ "movq 32(%%rax), %%rcx\n\t" \ "movq 24(%%rax), %%rdx\n\t" \ "movq 16(%%rax), %%rsi\n\t" \ "movq 8(%%rax), %%rdi\n\t" \ "movq (%%rax), %%rax\n\t" /* target->%rax */ \ VALGRIND_CALL_NOREDIR_RAX \ VALGRIND_RESTORE_STACK \ VALGRIND_CFI_EPILOGUE \ : /*out*/ "=a" (_res) \ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r14", "r15" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[10]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ _argvec[9] = (unsigned long)(arg9); \ __asm__ volatile( \ VALGRIND_CFI_PROLOGUE \ VALGRIND_ALIGN_STACK \ "subq $136,%%rsp\n\t" \ "pushq 72(%%rax)\n\t" \ "pushq 64(%%rax)\n\t" \ "pushq 56(%%rax)\n\t" \ "movq 48(%%rax), %%r9\n\t" \ "movq 40(%%rax), %%r8\n\t" \ "movq 32(%%rax), %%rcx\n\t" \ "movq 24(%%rax), %%rdx\n\t" \ "movq 16(%%rax), %%rsi\n\t" \ "movq 8(%%rax), %%rdi\n\t" \ "movq (%%rax), %%rax\n\t" /* target->%rax */ \ VALGRIND_CALL_NOREDIR_RAX \ VALGRIND_RESTORE_STACK \ VALGRIND_CFI_EPILOGUE \ : /*out*/ "=a" (_res) \ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r14", "r15" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9,arg10) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[11]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ _argvec[9] = (unsigned long)(arg9); \ _argvec[10] = (unsigned long)(arg10); \ __asm__ volatile( \ VALGRIND_CFI_PROLOGUE \ VALGRIND_ALIGN_STACK \ "subq $128,%%rsp\n\t" \ "pushq 80(%%rax)\n\t" \ "pushq 72(%%rax)\n\t" \ "pushq 64(%%rax)\n\t" \ "pushq 56(%%rax)\n\t" \ "movq 48(%%rax), %%r9\n\t" \ "movq 40(%%rax), %%r8\n\t" \ "movq 32(%%rax), %%rcx\n\t" \ "movq 24(%%rax), %%rdx\n\t" \ "movq 16(%%rax), %%rsi\n\t" \ "movq 8(%%rax), %%rdi\n\t" \ "movq (%%rax), %%rax\n\t" /* target->%rax */ \ VALGRIND_CALL_NOREDIR_RAX \ VALGRIND_RESTORE_STACK \ VALGRIND_CFI_EPILOGUE \ : /*out*/ "=a" (_res) \ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r14", "r15" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9,arg10,arg11) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[12]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ _argvec[9] = (unsigned long)(arg9); \ _argvec[10] = (unsigned long)(arg10); \ _argvec[11] = (unsigned long)(arg11); \ __asm__ volatile( \ VALGRIND_CFI_PROLOGUE \ VALGRIND_ALIGN_STACK \ "subq $136,%%rsp\n\t" \ "pushq 88(%%rax)\n\t" \ "pushq 80(%%rax)\n\t" \ "pushq 72(%%rax)\n\t" \ "pushq 64(%%rax)\n\t" \ "pushq 56(%%rax)\n\t" \ "movq 48(%%rax), %%r9\n\t" \ "movq 40(%%rax), %%r8\n\t" \ "movq 32(%%rax), %%rcx\n\t" \ "movq 24(%%rax), %%rdx\n\t" \ "movq 16(%%rax), %%rsi\n\t" \ "movq 8(%%rax), %%rdi\n\t" \ "movq (%%rax), %%rax\n\t" /* target->%rax */ \ VALGRIND_CALL_NOREDIR_RAX \ VALGRIND_RESTORE_STACK \ VALGRIND_CFI_EPILOGUE \ : /*out*/ "=a" (_res) \ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r14", "r15" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9,arg10,arg11,arg12) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[13]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ _argvec[9] = (unsigned long)(arg9); \ _argvec[10] = (unsigned long)(arg10); \ _argvec[11] = (unsigned long)(arg11); \ _argvec[12] = (unsigned long)(arg12); \ __asm__ volatile( \ VALGRIND_CFI_PROLOGUE \ VALGRIND_ALIGN_STACK \ "subq $128,%%rsp\n\t" \ "pushq 96(%%rax)\n\t" \ "pushq 88(%%rax)\n\t" \ "pushq 80(%%rax)\n\t" \ "pushq 72(%%rax)\n\t" \ "pushq 64(%%rax)\n\t" \ "pushq 56(%%rax)\n\t" \ "movq 48(%%rax), %%r9\n\t" \ "movq 40(%%rax), %%r8\n\t" \ "movq 32(%%rax), %%rcx\n\t" \ "movq 24(%%rax), %%rdx\n\t" \ "movq 16(%%rax), %%rsi\n\t" \ "movq 8(%%rax), %%rdi\n\t" \ "movq (%%rax), %%rax\n\t" /* target->%rax */ \ VALGRIND_CALL_NOREDIR_RAX \ VALGRIND_RESTORE_STACK \ VALGRIND_CFI_EPILOGUE \ : /*out*/ "=a" (_res) \ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r14", "r15" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #endif /* PLAT_amd64_linux || PLAT_amd64_darwin || PLAT_amd64_solaris */ /* ------------------------ ppc32-linux ------------------------ */ #if defined(PLAT_ppc32_linux) /* This is useful for finding out about the on-stack stuff: extern int f9 ( int,int,int,int,int,int,int,int,int ); extern int f10 ( int,int,int,int,int,int,int,int,int,int ); extern int f11 ( int,int,int,int,int,int,int,int,int,int,int ); extern int f12 ( int,int,int,int,int,int,int,int,int,int,int,int ); int g9 ( void ) { return f9(11,22,33,44,55,66,77,88,99); } int g10 ( void ) { return f10(11,22,33,44,55,66,77,88,99,110); } int g11 ( void ) { return f11(11,22,33,44,55,66,77,88,99,110,121); } int g12 ( void ) { return f12(11,22,33,44,55,66,77,88,99,110,121,132); } */ /* ARGREGS: r3 r4 r5 r6 r7 r8 r9 r10 (the rest on stack somewhere) */ /* These regs are trashed by the hidden call. */ #define __CALLER_SAVED_REGS \ "lr", "ctr", "xer", \ "cr0", "cr1", "cr2", "cr3", "cr4", "cr5", "cr6", "cr7", \ "r0", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", \ "r11", "r12", "r13" /* Macros to save and align the stack before making a function call and restore it afterwards as gcc may not keep the stack pointer aligned if it doesn't realise calls are being made to other functions. */ #define VALGRIND_ALIGN_STACK \ "mr 28,1\n\t" \ "rlwinm 1,1,0,0,27\n\t" #define VALGRIND_RESTORE_STACK \ "mr 1,28\n\t" /* These CALL_FN_ macros assume that on ppc32-linux, sizeof(unsigned long) == 4. */ #define CALL_FN_W_v(lval, orig) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[1]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 11,%1\n\t" \ "lwz 11,0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ VALGRIND_RESTORE_STACK \ "mr %0,3" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_W(lval, orig, arg1) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[2]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)arg1; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 11,%1\n\t" \ "lwz 3,4(11)\n\t" /* arg1->r3 */ \ "lwz 11,0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ VALGRIND_RESTORE_STACK \ "mr %0,3" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WW(lval, orig, arg1,arg2) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)arg1; \ _argvec[2] = (unsigned long)arg2; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 11,%1\n\t" \ "lwz 3,4(11)\n\t" /* arg1->r3 */ \ "lwz 4,8(11)\n\t" \ "lwz 11,0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ VALGRIND_RESTORE_STACK \ "mr %0,3" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[4]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)arg1; \ _argvec[2] = (unsigned long)arg2; \ _argvec[3] = (unsigned long)arg3; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 11,%1\n\t" \ "lwz 3,4(11)\n\t" /* arg1->r3 */ \ "lwz 4,8(11)\n\t" \ "lwz 5,12(11)\n\t" \ "lwz 11,0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ VALGRIND_RESTORE_STACK \ "mr %0,3" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[5]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)arg1; \ _argvec[2] = (unsigned long)arg2; \ _argvec[3] = (unsigned long)arg3; \ _argvec[4] = (unsigned long)arg4; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 11,%1\n\t" \ "lwz 3,4(11)\n\t" /* arg1->r3 */ \ "lwz 4,8(11)\n\t" \ "lwz 5,12(11)\n\t" \ "lwz 6,16(11)\n\t" /* arg4->r6 */ \ "lwz 11,0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ VALGRIND_RESTORE_STACK \ "mr %0,3" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[6]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)arg1; \ _argvec[2] = (unsigned long)arg2; \ _argvec[3] = (unsigned long)arg3; \ _argvec[4] = (unsigned long)arg4; \ _argvec[5] = (unsigned long)arg5; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 11,%1\n\t" \ "lwz 3,4(11)\n\t" /* arg1->r3 */ \ "lwz 4,8(11)\n\t" \ "lwz 5,12(11)\n\t" \ "lwz 6,16(11)\n\t" /* arg4->r6 */ \ "lwz 7,20(11)\n\t" \ "lwz 11,0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ VALGRIND_RESTORE_STACK \ "mr %0,3" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[7]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)arg1; \ _argvec[2] = (unsigned long)arg2; \ _argvec[3] = (unsigned long)arg3; \ _argvec[4] = (unsigned long)arg4; \ _argvec[5] = (unsigned long)arg5; \ _argvec[6] = (unsigned long)arg6; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 11,%1\n\t" \ "lwz 3,4(11)\n\t" /* arg1->r3 */ \ "lwz 4,8(11)\n\t" \ "lwz 5,12(11)\n\t" \ "lwz 6,16(11)\n\t" /* arg4->r6 */ \ "lwz 7,20(11)\n\t" \ "lwz 8,24(11)\n\t" \ "lwz 11,0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ VALGRIND_RESTORE_STACK \ "mr %0,3" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[8]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)arg1; \ _argvec[2] = (unsigned long)arg2; \ _argvec[3] = (unsigned long)arg3; \ _argvec[4] = (unsigned long)arg4; \ _argvec[5] = (unsigned long)arg5; \ _argvec[6] = (unsigned long)arg6; \ _argvec[7] = (unsigned long)arg7; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 11,%1\n\t" \ "lwz 3,4(11)\n\t" /* arg1->r3 */ \ "lwz 4,8(11)\n\t" \ "lwz 5,12(11)\n\t" \ "lwz 6,16(11)\n\t" /* arg4->r6 */ \ "lwz 7,20(11)\n\t" \ "lwz 8,24(11)\n\t" \ "lwz 9,28(11)\n\t" \ "lwz 11,0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ VALGRIND_RESTORE_STACK \ "mr %0,3" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[9]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)arg1; \ _argvec[2] = (unsigned long)arg2; \ _argvec[3] = (unsigned long)arg3; \ _argvec[4] = (unsigned long)arg4; \ _argvec[5] = (unsigned long)arg5; \ _argvec[6] = (unsigned long)arg6; \ _argvec[7] = (unsigned long)arg7; \ _argvec[8] = (unsigned long)arg8; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 11,%1\n\t" \ "lwz 3,4(11)\n\t" /* arg1->r3 */ \ "lwz 4,8(11)\n\t" \ "lwz 5,12(11)\n\t" \ "lwz 6,16(11)\n\t" /* arg4->r6 */ \ "lwz 7,20(11)\n\t" \ "lwz 8,24(11)\n\t" \ "lwz 9,28(11)\n\t" \ "lwz 10,32(11)\n\t" /* arg8->r10 */ \ "lwz 11,0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ VALGRIND_RESTORE_STACK \ "mr %0,3" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[10]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)arg1; \ _argvec[2] = (unsigned long)arg2; \ _argvec[3] = (unsigned long)arg3; \ _argvec[4] = (unsigned long)arg4; \ _argvec[5] = (unsigned long)arg5; \ _argvec[6] = (unsigned long)arg6; \ _argvec[7] = (unsigned long)arg7; \ _argvec[8] = (unsigned long)arg8; \ _argvec[9] = (unsigned long)arg9; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 11,%1\n\t" \ "addi 1,1,-16\n\t" \ /* arg9 */ \ "lwz 3,36(11)\n\t" \ "stw 3,8(1)\n\t" \ /* args1-8 */ \ "lwz 3,4(11)\n\t" /* arg1->r3 */ \ "lwz 4,8(11)\n\t" \ "lwz 5,12(11)\n\t" \ "lwz 6,16(11)\n\t" /* arg4->r6 */ \ "lwz 7,20(11)\n\t" \ "lwz 8,24(11)\n\t" \ "lwz 9,28(11)\n\t" \ "lwz 10,32(11)\n\t" /* arg8->r10 */ \ "lwz 11,0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ VALGRIND_RESTORE_STACK \ "mr %0,3" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9,arg10) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[11]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)arg1; \ _argvec[2] = (unsigned long)arg2; \ _argvec[3] = (unsigned long)arg3; \ _argvec[4] = (unsigned long)arg4; \ _argvec[5] = (unsigned long)arg5; \ _argvec[6] = (unsigned long)arg6; \ _argvec[7] = (unsigned long)arg7; \ _argvec[8] = (unsigned long)arg8; \ _argvec[9] = (unsigned long)arg9; \ _argvec[10] = (unsigned long)arg10; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 11,%1\n\t" \ "addi 1,1,-16\n\t" \ /* arg10 */ \ "lwz 3,40(11)\n\t" \ "stw 3,12(1)\n\t" \ /* arg9 */ \ "lwz 3,36(11)\n\t" \ "stw 3,8(1)\n\t" \ /* args1-8 */ \ "lwz 3,4(11)\n\t" /* arg1->r3 */ \ "lwz 4,8(11)\n\t" \ "lwz 5,12(11)\n\t" \ "lwz 6,16(11)\n\t" /* arg4->r6 */ \ "lwz 7,20(11)\n\t" \ "lwz 8,24(11)\n\t" \ "lwz 9,28(11)\n\t" \ "lwz 10,32(11)\n\t" /* arg8->r10 */ \ "lwz 11,0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ VALGRIND_RESTORE_STACK \ "mr %0,3" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9,arg10,arg11) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[12]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)arg1; \ _argvec[2] = (unsigned long)arg2; \ _argvec[3] = (unsigned long)arg3; \ _argvec[4] = (unsigned long)arg4; \ _argvec[5] = (unsigned long)arg5; \ _argvec[6] = (unsigned long)arg6; \ _argvec[7] = (unsigned long)arg7; \ _argvec[8] = (unsigned long)arg8; \ _argvec[9] = (unsigned long)arg9; \ _argvec[10] = (unsigned long)arg10; \ _argvec[11] = (unsigned long)arg11; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 11,%1\n\t" \ "addi 1,1,-32\n\t" \ /* arg11 */ \ "lwz 3,44(11)\n\t" \ "stw 3,16(1)\n\t" \ /* arg10 */ \ "lwz 3,40(11)\n\t" \ "stw 3,12(1)\n\t" \ /* arg9 */ \ "lwz 3,36(11)\n\t" \ "stw 3,8(1)\n\t" \ /* args1-8 */ \ "lwz 3,4(11)\n\t" /* arg1->r3 */ \ "lwz 4,8(11)\n\t" \ "lwz 5,12(11)\n\t" \ "lwz 6,16(11)\n\t" /* arg4->r6 */ \ "lwz 7,20(11)\n\t" \ "lwz 8,24(11)\n\t" \ "lwz 9,28(11)\n\t" \ "lwz 10,32(11)\n\t" /* arg8->r10 */ \ "lwz 11,0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ VALGRIND_RESTORE_STACK \ "mr %0,3" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9,arg10,arg11,arg12) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[13]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)arg1; \ _argvec[2] = (unsigned long)arg2; \ _argvec[3] = (unsigned long)arg3; \ _argvec[4] = (unsigned long)arg4; \ _argvec[5] = (unsigned long)arg5; \ _argvec[6] = (unsigned long)arg6; \ _argvec[7] = (unsigned long)arg7; \ _argvec[8] = (unsigned long)arg8; \ _argvec[9] = (unsigned long)arg9; \ _argvec[10] = (unsigned long)arg10; \ _argvec[11] = (unsigned long)arg11; \ _argvec[12] = (unsigned long)arg12; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 11,%1\n\t" \ "addi 1,1,-32\n\t" \ /* arg12 */ \ "lwz 3,48(11)\n\t" \ "stw 3,20(1)\n\t" \ /* arg11 */ \ "lwz 3,44(11)\n\t" \ "stw 3,16(1)\n\t" \ /* arg10 */ \ "lwz 3,40(11)\n\t" \ "stw 3,12(1)\n\t" \ /* arg9 */ \ "lwz 3,36(11)\n\t" \ "stw 3,8(1)\n\t" \ /* args1-8 */ \ "lwz 3,4(11)\n\t" /* arg1->r3 */ \ "lwz 4,8(11)\n\t" \ "lwz 5,12(11)\n\t" \ "lwz 6,16(11)\n\t" /* arg4->r6 */ \ "lwz 7,20(11)\n\t" \ "lwz 8,24(11)\n\t" \ "lwz 9,28(11)\n\t" \ "lwz 10,32(11)\n\t" /* arg8->r10 */ \ "lwz 11,0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ VALGRIND_RESTORE_STACK \ "mr %0,3" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #endif /* PLAT_ppc32_linux */ /* ------------------------ ppc64-linux ------------------------ */ #if defined(PLAT_ppc64be_linux) /* ARGREGS: r3 r4 r5 r6 r7 r8 r9 r10 (the rest on stack somewhere) */ /* These regs are trashed by the hidden call. */ #define __CALLER_SAVED_REGS \ "lr", "ctr", "xer", \ "cr0", "cr1", "cr2", "cr3", "cr4", "cr5", "cr6", "cr7", \ "r0", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", \ "r11", "r12", "r13" /* Macros to save and align the stack before making a function call and restore it afterwards as gcc may not keep the stack pointer aligned if it doesn't realise calls are being made to other functions. */ #define VALGRIND_ALIGN_STACK \ "mr 28,1\n\t" \ "rldicr 1,1,0,59\n\t" #define VALGRIND_RESTORE_STACK \ "mr 1,28\n\t" /* These CALL_FN_ macros assume that on ppc64-linux, sizeof(unsigned long) == 8. */ #define CALL_FN_W_v(lval, orig) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+0]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 11,%1\n\t" \ "std 2,-16(11)\n\t" /* save tocptr */ \ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ "ld 11, 0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ "mr 11,%1\n\t" \ "mr %0,3\n\t" \ "ld 2,-16(11)\n\t" /* restore tocptr */ \ VALGRIND_RESTORE_STACK \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_W(lval, orig, arg1) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+1]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2+1] = (unsigned long)arg1; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 11,%1\n\t" \ "std 2,-16(11)\n\t" /* save tocptr */ \ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ "ld 3, 8(11)\n\t" /* arg1->r3 */ \ "ld 11, 0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ "mr 11,%1\n\t" \ "mr %0,3\n\t" \ "ld 2,-16(11)\n\t" /* restore tocptr */ \ VALGRIND_RESTORE_STACK \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WW(lval, orig, arg1,arg2) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+2]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2+1] = (unsigned long)arg1; \ _argvec[2+2] = (unsigned long)arg2; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 11,%1\n\t" \ "std 2,-16(11)\n\t" /* save tocptr */ \ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ "ld 3, 8(11)\n\t" /* arg1->r3 */ \ "ld 4, 16(11)\n\t" /* arg2->r4 */ \ "ld 11, 0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ "mr 11,%1\n\t" \ "mr %0,3\n\t" \ "ld 2,-16(11)\n\t" /* restore tocptr */ \ VALGRIND_RESTORE_STACK \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+3]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2+1] = (unsigned long)arg1; \ _argvec[2+2] = (unsigned long)arg2; \ _argvec[2+3] = (unsigned long)arg3; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 11,%1\n\t" \ "std 2,-16(11)\n\t" /* save tocptr */ \ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ "ld 3, 8(11)\n\t" /* arg1->r3 */ \ "ld 4, 16(11)\n\t" /* arg2->r4 */ \ "ld 5, 24(11)\n\t" /* arg3->r5 */ \ "ld 11, 0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ "mr 11,%1\n\t" \ "mr %0,3\n\t" \ "ld 2,-16(11)\n\t" /* restore tocptr */ \ VALGRIND_RESTORE_STACK \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+4]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2+1] = (unsigned long)arg1; \ _argvec[2+2] = (unsigned long)arg2; \ _argvec[2+3] = (unsigned long)arg3; \ _argvec[2+4] = (unsigned long)arg4; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 11,%1\n\t" \ "std 2,-16(11)\n\t" /* save tocptr */ \ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ "ld 3, 8(11)\n\t" /* arg1->r3 */ \ "ld 4, 16(11)\n\t" /* arg2->r4 */ \ "ld 5, 24(11)\n\t" /* arg3->r5 */ \ "ld 6, 32(11)\n\t" /* arg4->r6 */ \ "ld 11, 0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ "mr 11,%1\n\t" \ "mr %0,3\n\t" \ "ld 2,-16(11)\n\t" /* restore tocptr */ \ VALGRIND_RESTORE_STACK \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+5]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2+1] = (unsigned long)arg1; \ _argvec[2+2] = (unsigned long)arg2; \ _argvec[2+3] = (unsigned long)arg3; \ _argvec[2+4] = (unsigned long)arg4; \ _argvec[2+5] = (unsigned long)arg5; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 11,%1\n\t" \ "std 2,-16(11)\n\t" /* save tocptr */ \ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ "ld 3, 8(11)\n\t" /* arg1->r3 */ \ "ld 4, 16(11)\n\t" /* arg2->r4 */ \ "ld 5, 24(11)\n\t" /* arg3->r5 */ \ "ld 6, 32(11)\n\t" /* arg4->r6 */ \ "ld 7, 40(11)\n\t" /* arg5->r7 */ \ "ld 11, 0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ "mr 11,%1\n\t" \ "mr %0,3\n\t" \ "ld 2,-16(11)\n\t" /* restore tocptr */ \ VALGRIND_RESTORE_STACK \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+6]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2+1] = (unsigned long)arg1; \ _argvec[2+2] = (unsigned long)arg2; \ _argvec[2+3] = (unsigned long)arg3; \ _argvec[2+4] = (unsigned long)arg4; \ _argvec[2+5] = (unsigned long)arg5; \ _argvec[2+6] = (unsigned long)arg6; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 11,%1\n\t" \ "std 2,-16(11)\n\t" /* save tocptr */ \ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ "ld 3, 8(11)\n\t" /* arg1->r3 */ \ "ld 4, 16(11)\n\t" /* arg2->r4 */ \ "ld 5, 24(11)\n\t" /* arg3->r5 */ \ "ld 6, 32(11)\n\t" /* arg4->r6 */ \ "ld 7, 40(11)\n\t" /* arg5->r7 */ \ "ld 8, 48(11)\n\t" /* arg6->r8 */ \ "ld 11, 0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ "mr 11,%1\n\t" \ "mr %0,3\n\t" \ "ld 2,-16(11)\n\t" /* restore tocptr */ \ VALGRIND_RESTORE_STACK \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+7]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2+1] = (unsigned long)arg1; \ _argvec[2+2] = (unsigned long)arg2; \ _argvec[2+3] = (unsigned long)arg3; \ _argvec[2+4] = (unsigned long)arg4; \ _argvec[2+5] = (unsigned long)arg5; \ _argvec[2+6] = (unsigned long)arg6; \ _argvec[2+7] = (unsigned long)arg7; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 11,%1\n\t" \ "std 2,-16(11)\n\t" /* save tocptr */ \ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ "ld 3, 8(11)\n\t" /* arg1->r3 */ \ "ld 4, 16(11)\n\t" /* arg2->r4 */ \ "ld 5, 24(11)\n\t" /* arg3->r5 */ \ "ld 6, 32(11)\n\t" /* arg4->r6 */ \ "ld 7, 40(11)\n\t" /* arg5->r7 */ \ "ld 8, 48(11)\n\t" /* arg6->r8 */ \ "ld 9, 56(11)\n\t" /* arg7->r9 */ \ "ld 11, 0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ "mr 11,%1\n\t" \ "mr %0,3\n\t" \ "ld 2,-16(11)\n\t" /* restore tocptr */ \ VALGRIND_RESTORE_STACK \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+8]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2+1] = (unsigned long)arg1; \ _argvec[2+2] = (unsigned long)arg2; \ _argvec[2+3] = (unsigned long)arg3; \ _argvec[2+4] = (unsigned long)arg4; \ _argvec[2+5] = (unsigned long)arg5; \ _argvec[2+6] = (unsigned long)arg6; \ _argvec[2+7] = (unsigned long)arg7; \ _argvec[2+8] = (unsigned long)arg8; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 11,%1\n\t" \ "std 2,-16(11)\n\t" /* save tocptr */ \ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ "ld 3, 8(11)\n\t" /* arg1->r3 */ \ "ld 4, 16(11)\n\t" /* arg2->r4 */ \ "ld 5, 24(11)\n\t" /* arg3->r5 */ \ "ld 6, 32(11)\n\t" /* arg4->r6 */ \ "ld 7, 40(11)\n\t" /* arg5->r7 */ \ "ld 8, 48(11)\n\t" /* arg6->r8 */ \ "ld 9, 56(11)\n\t" /* arg7->r9 */ \ "ld 10, 64(11)\n\t" /* arg8->r10 */ \ "ld 11, 0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ "mr 11,%1\n\t" \ "mr %0,3\n\t" \ "ld 2,-16(11)\n\t" /* restore tocptr */ \ VALGRIND_RESTORE_STACK \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+9]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2+1] = (unsigned long)arg1; \ _argvec[2+2] = (unsigned long)arg2; \ _argvec[2+3] = (unsigned long)arg3; \ _argvec[2+4] = (unsigned long)arg4; \ _argvec[2+5] = (unsigned long)arg5; \ _argvec[2+6] = (unsigned long)arg6; \ _argvec[2+7] = (unsigned long)arg7; \ _argvec[2+8] = (unsigned long)arg8; \ _argvec[2+9] = (unsigned long)arg9; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 11,%1\n\t" \ "std 2,-16(11)\n\t" /* save tocptr */ \ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ "addi 1,1,-128\n\t" /* expand stack frame */ \ /* arg9 */ \ "ld 3,72(11)\n\t" \ "std 3,112(1)\n\t" \ /* args1-8 */ \ "ld 3, 8(11)\n\t" /* arg1->r3 */ \ "ld 4, 16(11)\n\t" /* arg2->r4 */ \ "ld 5, 24(11)\n\t" /* arg3->r5 */ \ "ld 6, 32(11)\n\t" /* arg4->r6 */ \ "ld 7, 40(11)\n\t" /* arg5->r7 */ \ "ld 8, 48(11)\n\t" /* arg6->r8 */ \ "ld 9, 56(11)\n\t" /* arg7->r9 */ \ "ld 10, 64(11)\n\t" /* arg8->r10 */ \ "ld 11, 0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ "mr 11,%1\n\t" \ "mr %0,3\n\t" \ "ld 2,-16(11)\n\t" /* restore tocptr */ \ VALGRIND_RESTORE_STACK \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9,arg10) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+10]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2+1] = (unsigned long)arg1; \ _argvec[2+2] = (unsigned long)arg2; \ _argvec[2+3] = (unsigned long)arg3; \ _argvec[2+4] = (unsigned long)arg4; \ _argvec[2+5] = (unsigned long)arg5; \ _argvec[2+6] = (unsigned long)arg6; \ _argvec[2+7] = (unsigned long)arg7; \ _argvec[2+8] = (unsigned long)arg8; \ _argvec[2+9] = (unsigned long)arg9; \ _argvec[2+10] = (unsigned long)arg10; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 11,%1\n\t" \ "std 2,-16(11)\n\t" /* save tocptr */ \ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ "addi 1,1,-128\n\t" /* expand stack frame */ \ /* arg10 */ \ "ld 3,80(11)\n\t" \ "std 3,120(1)\n\t" \ /* arg9 */ \ "ld 3,72(11)\n\t" \ "std 3,112(1)\n\t" \ /* args1-8 */ \ "ld 3, 8(11)\n\t" /* arg1->r3 */ \ "ld 4, 16(11)\n\t" /* arg2->r4 */ \ "ld 5, 24(11)\n\t" /* arg3->r5 */ \ "ld 6, 32(11)\n\t" /* arg4->r6 */ \ "ld 7, 40(11)\n\t" /* arg5->r7 */ \ "ld 8, 48(11)\n\t" /* arg6->r8 */ \ "ld 9, 56(11)\n\t" /* arg7->r9 */ \ "ld 10, 64(11)\n\t" /* arg8->r10 */ \ "ld 11, 0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ "mr 11,%1\n\t" \ "mr %0,3\n\t" \ "ld 2,-16(11)\n\t" /* restore tocptr */ \ VALGRIND_RESTORE_STACK \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9,arg10,arg11) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+11]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2+1] = (unsigned long)arg1; \ _argvec[2+2] = (unsigned long)arg2; \ _argvec[2+3] = (unsigned long)arg3; \ _argvec[2+4] = (unsigned long)arg4; \ _argvec[2+5] = (unsigned long)arg5; \ _argvec[2+6] = (unsigned long)arg6; \ _argvec[2+7] = (unsigned long)arg7; \ _argvec[2+8] = (unsigned long)arg8; \ _argvec[2+9] = (unsigned long)arg9; \ _argvec[2+10] = (unsigned long)arg10; \ _argvec[2+11] = (unsigned long)arg11; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 11,%1\n\t" \ "std 2,-16(11)\n\t" /* save tocptr */ \ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ "addi 1,1,-144\n\t" /* expand stack frame */ \ /* arg11 */ \ "ld 3,88(11)\n\t" \ "std 3,128(1)\n\t" \ /* arg10 */ \ "ld 3,80(11)\n\t" \ "std 3,120(1)\n\t" \ /* arg9 */ \ "ld 3,72(11)\n\t" \ "std 3,112(1)\n\t" \ /* args1-8 */ \ "ld 3, 8(11)\n\t" /* arg1->r3 */ \ "ld 4, 16(11)\n\t" /* arg2->r4 */ \ "ld 5, 24(11)\n\t" /* arg3->r5 */ \ "ld 6, 32(11)\n\t" /* arg4->r6 */ \ "ld 7, 40(11)\n\t" /* arg5->r7 */ \ "ld 8, 48(11)\n\t" /* arg6->r8 */ \ "ld 9, 56(11)\n\t" /* arg7->r9 */ \ "ld 10, 64(11)\n\t" /* arg8->r10 */ \ "ld 11, 0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ "mr 11,%1\n\t" \ "mr %0,3\n\t" \ "ld 2,-16(11)\n\t" /* restore tocptr */ \ VALGRIND_RESTORE_STACK \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9,arg10,arg11,arg12) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+12]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2+1] = (unsigned long)arg1; \ _argvec[2+2] = (unsigned long)arg2; \ _argvec[2+3] = (unsigned long)arg3; \ _argvec[2+4] = (unsigned long)arg4; \ _argvec[2+5] = (unsigned long)arg5; \ _argvec[2+6] = (unsigned long)arg6; \ _argvec[2+7] = (unsigned long)arg7; \ _argvec[2+8] = (unsigned long)arg8; \ _argvec[2+9] = (unsigned long)arg9; \ _argvec[2+10] = (unsigned long)arg10; \ _argvec[2+11] = (unsigned long)arg11; \ _argvec[2+12] = (unsigned long)arg12; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 11,%1\n\t" \ "std 2,-16(11)\n\t" /* save tocptr */ \ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ "addi 1,1,-144\n\t" /* expand stack frame */ \ /* arg12 */ \ "ld 3,96(11)\n\t" \ "std 3,136(1)\n\t" \ /* arg11 */ \ "ld 3,88(11)\n\t" \ "std 3,128(1)\n\t" \ /* arg10 */ \ "ld 3,80(11)\n\t" \ "std 3,120(1)\n\t" \ /* arg9 */ \ "ld 3,72(11)\n\t" \ "std 3,112(1)\n\t" \ /* args1-8 */ \ "ld 3, 8(11)\n\t" /* arg1->r3 */ \ "ld 4, 16(11)\n\t" /* arg2->r4 */ \ "ld 5, 24(11)\n\t" /* arg3->r5 */ \ "ld 6, 32(11)\n\t" /* arg4->r6 */ \ "ld 7, 40(11)\n\t" /* arg5->r7 */ \ "ld 8, 48(11)\n\t" /* arg6->r8 */ \ "ld 9, 56(11)\n\t" /* arg7->r9 */ \ "ld 10, 64(11)\n\t" /* arg8->r10 */ \ "ld 11, 0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ "mr 11,%1\n\t" \ "mr %0,3\n\t" \ "ld 2,-16(11)\n\t" /* restore tocptr */ \ VALGRIND_RESTORE_STACK \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #endif /* PLAT_ppc64be_linux */ /* ------------------------- ppc64le-linux ----------------------- */ #if defined(PLAT_ppc64le_linux) /* ARGREGS: r3 r4 r5 r6 r7 r8 r9 r10 (the rest on stack somewhere) */ /* These regs are trashed by the hidden call. */ #define __CALLER_SAVED_REGS \ "lr", "ctr", "xer", \ "cr0", "cr1", "cr2", "cr3", "cr4", "cr5", "cr6", "cr7", \ "r0", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", \ "r11", "r12", "r13" /* Macros to save and align the stack before making a function call and restore it afterwards as gcc may not keep the stack pointer aligned if it doesn't realise calls are being made to other functions. */ #define VALGRIND_ALIGN_STACK \ "mr 28,1\n\t" \ "rldicr 1,1,0,59\n\t" #define VALGRIND_RESTORE_STACK \ "mr 1,28\n\t" /* These CALL_FN_ macros assume that on ppc64-linux, sizeof(unsigned long) == 8. */ #define CALL_FN_W_v(lval, orig) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+0]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 12,%1\n\t" \ "std 2,-16(12)\n\t" /* save tocptr */ \ "ld 2,-8(12)\n\t" /* use nraddr's tocptr */ \ "ld 12, 0(12)\n\t" /* target->r12 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R12 \ "mr 12,%1\n\t" \ "mr %0,3\n\t" \ "ld 2,-16(12)\n\t" /* restore tocptr */ \ VALGRIND_RESTORE_STACK \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_W(lval, orig, arg1) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+1]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2+1] = (unsigned long)arg1; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 12,%1\n\t" \ "std 2,-16(12)\n\t" /* save tocptr */ \ "ld 2,-8(12)\n\t" /* use nraddr's tocptr */ \ "ld 3, 8(12)\n\t" /* arg1->r3 */ \ "ld 12, 0(12)\n\t" /* target->r12 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R12 \ "mr 12,%1\n\t" \ "mr %0,3\n\t" \ "ld 2,-16(12)\n\t" /* restore tocptr */ \ VALGRIND_RESTORE_STACK \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WW(lval, orig, arg1,arg2) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+2]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2+1] = (unsigned long)arg1; \ _argvec[2+2] = (unsigned long)arg2; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 12,%1\n\t" \ "std 2,-16(12)\n\t" /* save tocptr */ \ "ld 2,-8(12)\n\t" /* use nraddr's tocptr */ \ "ld 3, 8(12)\n\t" /* arg1->r3 */ \ "ld 4, 16(12)\n\t" /* arg2->r4 */ \ "ld 12, 0(12)\n\t" /* target->r12 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R12 \ "mr 12,%1\n\t" \ "mr %0,3\n\t" \ "ld 2,-16(12)\n\t" /* restore tocptr */ \ VALGRIND_RESTORE_STACK \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+3]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2+1] = (unsigned long)arg1; \ _argvec[2+2] = (unsigned long)arg2; \ _argvec[2+3] = (unsigned long)arg3; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 12,%1\n\t" \ "std 2,-16(12)\n\t" /* save tocptr */ \ "ld 2,-8(12)\n\t" /* use nraddr's tocptr */ \ "ld 3, 8(12)\n\t" /* arg1->r3 */ \ "ld 4, 16(12)\n\t" /* arg2->r4 */ \ "ld 5, 24(12)\n\t" /* arg3->r5 */ \ "ld 12, 0(12)\n\t" /* target->r12 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R12 \ "mr 12,%1\n\t" \ "mr %0,3\n\t" \ "ld 2,-16(12)\n\t" /* restore tocptr */ \ VALGRIND_RESTORE_STACK \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+4]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2+1] = (unsigned long)arg1; \ _argvec[2+2] = (unsigned long)arg2; \ _argvec[2+3] = (unsigned long)arg3; \ _argvec[2+4] = (unsigned long)arg4; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 12,%1\n\t" \ "std 2,-16(12)\n\t" /* save tocptr */ \ "ld 2,-8(12)\n\t" /* use nraddr's tocptr */ \ "ld 3, 8(12)\n\t" /* arg1->r3 */ \ "ld 4, 16(12)\n\t" /* arg2->r4 */ \ "ld 5, 24(12)\n\t" /* arg3->r5 */ \ "ld 6, 32(12)\n\t" /* arg4->r6 */ \ "ld 12, 0(12)\n\t" /* target->r12 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R12 \ "mr 12,%1\n\t" \ "mr %0,3\n\t" \ "ld 2,-16(12)\n\t" /* restore tocptr */ \ VALGRIND_RESTORE_STACK \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+5]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2+1] = (unsigned long)arg1; \ _argvec[2+2] = (unsigned long)arg2; \ _argvec[2+3] = (unsigned long)arg3; \ _argvec[2+4] = (unsigned long)arg4; \ _argvec[2+5] = (unsigned long)arg5; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 12,%1\n\t" \ "std 2,-16(12)\n\t" /* save tocptr */ \ "ld 2,-8(12)\n\t" /* use nraddr's tocptr */ \ "ld 3, 8(12)\n\t" /* arg1->r3 */ \ "ld 4, 16(12)\n\t" /* arg2->r4 */ \ "ld 5, 24(12)\n\t" /* arg3->r5 */ \ "ld 6, 32(12)\n\t" /* arg4->r6 */ \ "ld 7, 40(12)\n\t" /* arg5->r7 */ \ "ld 12, 0(12)\n\t" /* target->r12 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R12 \ "mr 12,%1\n\t" \ "mr %0,3\n\t" \ "ld 2,-16(12)\n\t" /* restore tocptr */ \ VALGRIND_RESTORE_STACK \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+6]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2+1] = (unsigned long)arg1; \ _argvec[2+2] = (unsigned long)arg2; \ _argvec[2+3] = (unsigned long)arg3; \ _argvec[2+4] = (unsigned long)arg4; \ _argvec[2+5] = (unsigned long)arg5; \ _argvec[2+6] = (unsigned long)arg6; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 12,%1\n\t" \ "std 2,-16(12)\n\t" /* save tocptr */ \ "ld 2,-8(12)\n\t" /* use nraddr's tocptr */ \ "ld 3, 8(12)\n\t" /* arg1->r3 */ \ "ld 4, 16(12)\n\t" /* arg2->r4 */ \ "ld 5, 24(12)\n\t" /* arg3->r5 */ \ "ld 6, 32(12)\n\t" /* arg4->r6 */ \ "ld 7, 40(12)\n\t" /* arg5->r7 */ \ "ld 8, 48(12)\n\t" /* arg6->r8 */ \ "ld 12, 0(12)\n\t" /* target->r12 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R12 \ "mr 12,%1\n\t" \ "mr %0,3\n\t" \ "ld 2,-16(12)\n\t" /* restore tocptr */ \ VALGRIND_RESTORE_STACK \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+7]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2+1] = (unsigned long)arg1; \ _argvec[2+2] = (unsigned long)arg2; \ _argvec[2+3] = (unsigned long)arg3; \ _argvec[2+4] = (unsigned long)arg4; \ _argvec[2+5] = (unsigned long)arg5; \ _argvec[2+6] = (unsigned long)arg6; \ _argvec[2+7] = (unsigned long)arg7; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 12,%1\n\t" \ "std 2,-16(12)\n\t" /* save tocptr */ \ "ld 2,-8(12)\n\t" /* use nraddr's tocptr */ \ "ld 3, 8(12)\n\t" /* arg1->r3 */ \ "ld 4, 16(12)\n\t" /* arg2->r4 */ \ "ld 5, 24(12)\n\t" /* arg3->r5 */ \ "ld 6, 32(12)\n\t" /* arg4->r6 */ \ "ld 7, 40(12)\n\t" /* arg5->r7 */ \ "ld 8, 48(12)\n\t" /* arg6->r8 */ \ "ld 9, 56(12)\n\t" /* arg7->r9 */ \ "ld 12, 0(12)\n\t" /* target->r12 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R12 \ "mr 12,%1\n\t" \ "mr %0,3\n\t" \ "ld 2,-16(12)\n\t" /* restore tocptr */ \ VALGRIND_RESTORE_STACK \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+8]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2+1] = (unsigned long)arg1; \ _argvec[2+2] = (unsigned long)arg2; \ _argvec[2+3] = (unsigned long)arg3; \ _argvec[2+4] = (unsigned long)arg4; \ _argvec[2+5] = (unsigned long)arg5; \ _argvec[2+6] = (unsigned long)arg6; \ _argvec[2+7] = (unsigned long)arg7; \ _argvec[2+8] = (unsigned long)arg8; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 12,%1\n\t" \ "std 2,-16(12)\n\t" /* save tocptr */ \ "ld 2,-8(12)\n\t" /* use nraddr's tocptr */ \ "ld 3, 8(12)\n\t" /* arg1->r3 */ \ "ld 4, 16(12)\n\t" /* arg2->r4 */ \ "ld 5, 24(12)\n\t" /* arg3->r5 */ \ "ld 6, 32(12)\n\t" /* arg4->r6 */ \ "ld 7, 40(12)\n\t" /* arg5->r7 */ \ "ld 8, 48(12)\n\t" /* arg6->r8 */ \ "ld 9, 56(12)\n\t" /* arg7->r9 */ \ "ld 10, 64(12)\n\t" /* arg8->r10 */ \ "ld 12, 0(12)\n\t" /* target->r12 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R12 \ "mr 12,%1\n\t" \ "mr %0,3\n\t" \ "ld 2,-16(12)\n\t" /* restore tocptr */ \ VALGRIND_RESTORE_STACK \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+9]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2+1] = (unsigned long)arg1; \ _argvec[2+2] = (unsigned long)arg2; \ _argvec[2+3] = (unsigned long)arg3; \ _argvec[2+4] = (unsigned long)arg4; \ _argvec[2+5] = (unsigned long)arg5; \ _argvec[2+6] = (unsigned long)arg6; \ _argvec[2+7] = (unsigned long)arg7; \ _argvec[2+8] = (unsigned long)arg8; \ _argvec[2+9] = (unsigned long)arg9; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 12,%1\n\t" \ "std 2,-16(12)\n\t" /* save tocptr */ \ "ld 2,-8(12)\n\t" /* use nraddr's tocptr */ \ "addi 1,1,-128\n\t" /* expand stack frame */ \ /* arg9 */ \ "ld 3,72(12)\n\t" \ "std 3,96(1)\n\t" \ /* args1-8 */ \ "ld 3, 8(12)\n\t" /* arg1->r3 */ \ "ld 4, 16(12)\n\t" /* arg2->r4 */ \ "ld 5, 24(12)\n\t" /* arg3->r5 */ \ "ld 6, 32(12)\n\t" /* arg4->r6 */ \ "ld 7, 40(12)\n\t" /* arg5->r7 */ \ "ld 8, 48(12)\n\t" /* arg6->r8 */ \ "ld 9, 56(12)\n\t" /* arg7->r9 */ \ "ld 10, 64(12)\n\t" /* arg8->r10 */ \ "ld 12, 0(12)\n\t" /* target->r12 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R12 \ "mr 12,%1\n\t" \ "mr %0,3\n\t" \ "ld 2,-16(12)\n\t" /* restore tocptr */ \ VALGRIND_RESTORE_STACK \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9,arg10) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+10]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2+1] = (unsigned long)arg1; \ _argvec[2+2] = (unsigned long)arg2; \ _argvec[2+3] = (unsigned long)arg3; \ _argvec[2+4] = (unsigned long)arg4; \ _argvec[2+5] = (unsigned long)arg5; \ _argvec[2+6] = (unsigned long)arg6; \ _argvec[2+7] = (unsigned long)arg7; \ _argvec[2+8] = (unsigned long)arg8; \ _argvec[2+9] = (unsigned long)arg9; \ _argvec[2+10] = (unsigned long)arg10; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 12,%1\n\t" \ "std 2,-16(12)\n\t" /* save tocptr */ \ "ld 2,-8(12)\n\t" /* use nraddr's tocptr */ \ "addi 1,1,-128\n\t" /* expand stack frame */ \ /* arg10 */ \ "ld 3,80(12)\n\t" \ "std 3,104(1)\n\t" \ /* arg9 */ \ "ld 3,72(12)\n\t" \ "std 3,96(1)\n\t" \ /* args1-8 */ \ "ld 3, 8(12)\n\t" /* arg1->r3 */ \ "ld 4, 16(12)\n\t" /* arg2->r4 */ \ "ld 5, 24(12)\n\t" /* arg3->r5 */ \ "ld 6, 32(12)\n\t" /* arg4->r6 */ \ "ld 7, 40(12)\n\t" /* arg5->r7 */ \ "ld 8, 48(12)\n\t" /* arg6->r8 */ \ "ld 9, 56(12)\n\t" /* arg7->r9 */ \ "ld 10, 64(12)\n\t" /* arg8->r10 */ \ "ld 12, 0(12)\n\t" /* target->r12 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R12 \ "mr 12,%1\n\t" \ "mr %0,3\n\t" \ "ld 2,-16(12)\n\t" /* restore tocptr */ \ VALGRIND_RESTORE_STACK \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9,arg10,arg11) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+11]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2+1] = (unsigned long)arg1; \ _argvec[2+2] = (unsigned long)arg2; \ _argvec[2+3] = (unsigned long)arg3; \ _argvec[2+4] = (unsigned long)arg4; \ _argvec[2+5] = (unsigned long)arg5; \ _argvec[2+6] = (unsigned long)arg6; \ _argvec[2+7] = (unsigned long)arg7; \ _argvec[2+8] = (unsigned long)arg8; \ _argvec[2+9] = (unsigned long)arg9; \ _argvec[2+10] = (unsigned long)arg10; \ _argvec[2+11] = (unsigned long)arg11; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 12,%1\n\t" \ "std 2,-16(12)\n\t" /* save tocptr */ \ "ld 2,-8(12)\n\t" /* use nraddr's tocptr */ \ "addi 1,1,-144\n\t" /* expand stack frame */ \ /* arg11 */ \ "ld 3,88(12)\n\t" \ "std 3,112(1)\n\t" \ /* arg10 */ \ "ld 3,80(12)\n\t" \ "std 3,104(1)\n\t" \ /* arg9 */ \ "ld 3,72(12)\n\t" \ "std 3,96(1)\n\t" \ /* args1-8 */ \ "ld 3, 8(12)\n\t" /* arg1->r3 */ \ "ld 4, 16(12)\n\t" /* arg2->r4 */ \ "ld 5, 24(12)\n\t" /* arg3->r5 */ \ "ld 6, 32(12)\n\t" /* arg4->r6 */ \ "ld 7, 40(12)\n\t" /* arg5->r7 */ \ "ld 8, 48(12)\n\t" /* arg6->r8 */ \ "ld 9, 56(12)\n\t" /* arg7->r9 */ \ "ld 10, 64(12)\n\t" /* arg8->r10 */ \ "ld 12, 0(12)\n\t" /* target->r12 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R12 \ "mr 12,%1\n\t" \ "mr %0,3\n\t" \ "ld 2,-16(12)\n\t" /* restore tocptr */ \ VALGRIND_RESTORE_STACK \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9,arg10,arg11,arg12) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+12]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2+1] = (unsigned long)arg1; \ _argvec[2+2] = (unsigned long)arg2; \ _argvec[2+3] = (unsigned long)arg3; \ _argvec[2+4] = (unsigned long)arg4; \ _argvec[2+5] = (unsigned long)arg5; \ _argvec[2+6] = (unsigned long)arg6; \ _argvec[2+7] = (unsigned long)arg7; \ _argvec[2+8] = (unsigned long)arg8; \ _argvec[2+9] = (unsigned long)arg9; \ _argvec[2+10] = (unsigned long)arg10; \ _argvec[2+11] = (unsigned long)arg11; \ _argvec[2+12] = (unsigned long)arg12; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 12,%1\n\t" \ "std 2,-16(12)\n\t" /* save tocptr */ \ "ld 2,-8(12)\n\t" /* use nraddr's tocptr */ \ "addi 1,1,-144\n\t" /* expand stack frame */ \ /* arg12 */ \ "ld 3,96(12)\n\t" \ "std 3,120(1)\n\t" \ /* arg11 */ \ "ld 3,88(12)\n\t" \ "std 3,112(1)\n\t" \ /* arg10 */ \ "ld 3,80(12)\n\t" \ "std 3,104(1)\n\t" \ /* arg9 */ \ "ld 3,72(12)\n\t" \ "std 3,96(1)\n\t" \ /* args1-8 */ \ "ld 3, 8(12)\n\t" /* arg1->r3 */ \ "ld 4, 16(12)\n\t" /* arg2->r4 */ \ "ld 5, 24(12)\n\t" /* arg3->r5 */ \ "ld 6, 32(12)\n\t" /* arg4->r6 */ \ "ld 7, 40(12)\n\t" /* arg5->r7 */ \ "ld 8, 48(12)\n\t" /* arg6->r8 */ \ "ld 9, 56(12)\n\t" /* arg7->r9 */ \ "ld 10, 64(12)\n\t" /* arg8->r10 */ \ "ld 12, 0(12)\n\t" /* target->r12 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R12 \ "mr 12,%1\n\t" \ "mr %0,3\n\t" \ "ld 2,-16(12)\n\t" /* restore tocptr */ \ VALGRIND_RESTORE_STACK \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #endif /* PLAT_ppc64le_linux */ /* ------------------------- arm-linux ------------------------- */ #if defined(PLAT_arm_linux) /* These regs are trashed by the hidden call. */ #define __CALLER_SAVED_REGS "r0", "r1", "r2", "r3","r4", "r12", "r14" /* Macros to save and align the stack before making a function call and restore it afterwards as gcc may not keep the stack pointer aligned if it doesn't realise calls are being made to other functions. */ /* This is a bit tricky. We store the original stack pointer in r10 as it is callee-saves. gcc doesn't allow the use of r11 for some reason. Also, we can't directly "bic" the stack pointer in thumb mode since r13 isn't an allowed register number in that context. So use r4 as a temporary, since that is about to get trashed anyway, just after each use of this macro. Side effect is we need to be very careful about any future changes, since VALGRIND_ALIGN_STACK simply assumes r4 is usable. */ #define VALGRIND_ALIGN_STACK \ "mov r10, sp\n\t" \ "mov r4, sp\n\t" \ "bic r4, r4, #7\n\t" \ "mov sp, r4\n\t" #define VALGRIND_RESTORE_STACK \ "mov sp, r10\n\t" /* These CALL_FN_ macros assume that on arm-linux, sizeof(unsigned long) == 4. */ #define CALL_FN_W_v(lval, orig) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[1]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "ldr r4, [%1] \n\t" /* target->r4 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ VALGRIND_RESTORE_STACK \ "mov %0, r0\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r10" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_W(lval, orig, arg1) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[2]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "ldr r0, [%1, #4] \n\t" \ "ldr r4, [%1] \n\t" /* target->r4 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ VALGRIND_RESTORE_STACK \ "mov %0, r0\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r10" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WW(lval, orig, arg1,arg2) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "ldr r0, [%1, #4] \n\t" \ "ldr r1, [%1, #8] \n\t" \ "ldr r4, [%1] \n\t" /* target->r4 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ VALGRIND_RESTORE_STACK \ "mov %0, r0\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r10" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[4]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "ldr r0, [%1, #4] \n\t" \ "ldr r1, [%1, #8] \n\t" \ "ldr r2, [%1, #12] \n\t" \ "ldr r4, [%1] \n\t" /* target->r4 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ VALGRIND_RESTORE_STACK \ "mov %0, r0\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r10" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[5]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "ldr r0, [%1, #4] \n\t" \ "ldr r1, [%1, #8] \n\t" \ "ldr r2, [%1, #12] \n\t" \ "ldr r3, [%1, #16] \n\t" \ "ldr r4, [%1] \n\t" /* target->r4 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ VALGRIND_RESTORE_STACK \ "mov %0, r0" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r10" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[6]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "sub sp, sp, #4 \n\t" \ "ldr r0, [%1, #20] \n\t" \ "push {r0} \n\t" \ "ldr r0, [%1, #4] \n\t" \ "ldr r1, [%1, #8] \n\t" \ "ldr r2, [%1, #12] \n\t" \ "ldr r3, [%1, #16] \n\t" \ "ldr r4, [%1] \n\t" /* target->r4 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ VALGRIND_RESTORE_STACK \ "mov %0, r0" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r10" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[7]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "ldr r0, [%1, #20] \n\t" \ "ldr r1, [%1, #24] \n\t" \ "push {r0, r1} \n\t" \ "ldr r0, [%1, #4] \n\t" \ "ldr r1, [%1, #8] \n\t" \ "ldr r2, [%1, #12] \n\t" \ "ldr r3, [%1, #16] \n\t" \ "ldr r4, [%1] \n\t" /* target->r4 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ VALGRIND_RESTORE_STACK \ "mov %0, r0" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r10" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[8]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "sub sp, sp, #4 \n\t" \ "ldr r0, [%1, #20] \n\t" \ "ldr r1, [%1, #24] \n\t" \ "ldr r2, [%1, #28] \n\t" \ "push {r0, r1, r2} \n\t" \ "ldr r0, [%1, #4] \n\t" \ "ldr r1, [%1, #8] \n\t" \ "ldr r2, [%1, #12] \n\t" \ "ldr r3, [%1, #16] \n\t" \ "ldr r4, [%1] \n\t" /* target->r4 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ VALGRIND_RESTORE_STACK \ "mov %0, r0" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r10" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[9]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "ldr r0, [%1, #20] \n\t" \ "ldr r1, [%1, #24] \n\t" \ "ldr r2, [%1, #28] \n\t" \ "ldr r3, [%1, #32] \n\t" \ "push {r0, r1, r2, r3} \n\t" \ "ldr r0, [%1, #4] \n\t" \ "ldr r1, [%1, #8] \n\t" \ "ldr r2, [%1, #12] \n\t" \ "ldr r3, [%1, #16] \n\t" \ "ldr r4, [%1] \n\t" /* target->r4 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ VALGRIND_RESTORE_STACK \ "mov %0, r0" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r10" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[10]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ _argvec[9] = (unsigned long)(arg9); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "sub sp, sp, #4 \n\t" \ "ldr r0, [%1, #20] \n\t" \ "ldr r1, [%1, #24] \n\t" \ "ldr r2, [%1, #28] \n\t" \ "ldr r3, [%1, #32] \n\t" \ "ldr r4, [%1, #36] \n\t" \ "push {r0, r1, r2, r3, r4} \n\t" \ "ldr r0, [%1, #4] \n\t" \ "ldr r1, [%1, #8] \n\t" \ "ldr r2, [%1, #12] \n\t" \ "ldr r3, [%1, #16] \n\t" \ "ldr r4, [%1] \n\t" /* target->r4 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ VALGRIND_RESTORE_STACK \ "mov %0, r0" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r10" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9,arg10) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[11]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ _argvec[9] = (unsigned long)(arg9); \ _argvec[10] = (unsigned long)(arg10); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "ldr r0, [%1, #40] \n\t" \ "push {r0} \n\t" \ "ldr r0, [%1, #20] \n\t" \ "ldr r1, [%1, #24] \n\t" \ "ldr r2, [%1, #28] \n\t" \ "ldr r3, [%1, #32] \n\t" \ "ldr r4, [%1, #36] \n\t" \ "push {r0, r1, r2, r3, r4} \n\t" \ "ldr r0, [%1, #4] \n\t" \ "ldr r1, [%1, #8] \n\t" \ "ldr r2, [%1, #12] \n\t" \ "ldr r3, [%1, #16] \n\t" \ "ldr r4, [%1] \n\t" /* target->r4 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ VALGRIND_RESTORE_STACK \ "mov %0, r0" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r10" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5, \ arg6,arg7,arg8,arg9,arg10, \ arg11) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[12]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ _argvec[9] = (unsigned long)(arg9); \ _argvec[10] = (unsigned long)(arg10); \ _argvec[11] = (unsigned long)(arg11); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "sub sp, sp, #4 \n\t" \ "ldr r0, [%1, #40] \n\t" \ "ldr r1, [%1, #44] \n\t" \ "push {r0, r1} \n\t" \ "ldr r0, [%1, #20] \n\t" \ "ldr r1, [%1, #24] \n\t" \ "ldr r2, [%1, #28] \n\t" \ "ldr r3, [%1, #32] \n\t" \ "ldr r4, [%1, #36] \n\t" \ "push {r0, r1, r2, r3, r4} \n\t" \ "ldr r0, [%1, #4] \n\t" \ "ldr r1, [%1, #8] \n\t" \ "ldr r2, [%1, #12] \n\t" \ "ldr r3, [%1, #16] \n\t" \ "ldr r4, [%1] \n\t" /* target->r4 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ VALGRIND_RESTORE_STACK \ "mov %0, r0" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r10" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5, \ arg6,arg7,arg8,arg9,arg10, \ arg11,arg12) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[13]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ _argvec[9] = (unsigned long)(arg9); \ _argvec[10] = (unsigned long)(arg10); \ _argvec[11] = (unsigned long)(arg11); \ _argvec[12] = (unsigned long)(arg12); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "ldr r0, [%1, #40] \n\t" \ "ldr r1, [%1, #44] \n\t" \ "ldr r2, [%1, #48] \n\t" \ "push {r0, r1, r2} \n\t" \ "ldr r0, [%1, #20] \n\t" \ "ldr r1, [%1, #24] \n\t" \ "ldr r2, [%1, #28] \n\t" \ "ldr r3, [%1, #32] \n\t" \ "ldr r4, [%1, #36] \n\t" \ "push {r0, r1, r2, r3, r4} \n\t" \ "ldr r0, [%1, #4] \n\t" \ "ldr r1, [%1, #8] \n\t" \ "ldr r2, [%1, #12] \n\t" \ "ldr r3, [%1, #16] \n\t" \ "ldr r4, [%1] \n\t" /* target->r4 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ VALGRIND_RESTORE_STACK \ "mov %0, r0" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r10" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #endif /* PLAT_arm_linux */ /* ------------------------ arm64-linux ------------------------ */ #if defined(PLAT_arm64_linux) /* These regs are trashed by the hidden call. */ #define __CALLER_SAVED_REGS \ "x0", "x1", "x2", "x3","x4", "x5", "x6", "x7", "x8", "x9", \ "x10", "x11", "x12", "x13", "x14", "x15", "x16", "x17", \ "x18", "x19", "x20", "x30", \ "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8", "v9", \ "v10", "v11", "v12", "v13", "v14", "v15", "v16", "v17", \ "v18", "v19", "v20", "v21", "v22", "v23", "v24", "v25", \ "v26", "v27", "v28", "v29", "v30", "v31" /* x21 is callee-saved, so we can use it to save and restore SP around the hidden call. */ #define VALGRIND_ALIGN_STACK \ "mov x21, sp\n\t" \ "bic sp, x21, #15\n\t" #define VALGRIND_RESTORE_STACK \ "mov sp, x21\n\t" /* These CALL_FN_ macros assume that on arm64-linux, sizeof(unsigned long) == 8. */ #define CALL_FN_W_v(lval, orig) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[1]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "ldr x8, [%1] \n\t" /* target->x8 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_X8 \ VALGRIND_RESTORE_STACK \ "mov %0, x0\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "x21" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_W(lval, orig, arg1) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[2]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "ldr x0, [%1, #8] \n\t" \ "ldr x8, [%1] \n\t" /* target->x8 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_X8 \ VALGRIND_RESTORE_STACK \ "mov %0, x0\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "x21" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WW(lval, orig, arg1,arg2) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "ldr x0, [%1, #8] \n\t" \ "ldr x1, [%1, #16] \n\t" \ "ldr x8, [%1] \n\t" /* target->x8 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_X8 \ VALGRIND_RESTORE_STACK \ "mov %0, x0\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "x21" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[4]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "ldr x0, [%1, #8] \n\t" \ "ldr x1, [%1, #16] \n\t" \ "ldr x2, [%1, #24] \n\t" \ "ldr x8, [%1] \n\t" /* target->x8 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_X8 \ VALGRIND_RESTORE_STACK \ "mov %0, x0\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "x21" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[5]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "ldr x0, [%1, #8] \n\t" \ "ldr x1, [%1, #16] \n\t" \ "ldr x2, [%1, #24] \n\t" \ "ldr x3, [%1, #32] \n\t" \ "ldr x8, [%1] \n\t" /* target->x8 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_X8 \ VALGRIND_RESTORE_STACK \ "mov %0, x0" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "x21" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[6]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "ldr x0, [%1, #8] \n\t" \ "ldr x1, [%1, #16] \n\t" \ "ldr x2, [%1, #24] \n\t" \ "ldr x3, [%1, #32] \n\t" \ "ldr x4, [%1, #40] \n\t" \ "ldr x8, [%1] \n\t" /* target->x8 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_X8 \ VALGRIND_RESTORE_STACK \ "mov %0, x0" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "x21" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[7]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "ldr x0, [%1, #8] \n\t" \ "ldr x1, [%1, #16] \n\t" \ "ldr x2, [%1, #24] \n\t" \ "ldr x3, [%1, #32] \n\t" \ "ldr x4, [%1, #40] \n\t" \ "ldr x5, [%1, #48] \n\t" \ "ldr x8, [%1] \n\t" /* target->x8 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_X8 \ VALGRIND_RESTORE_STACK \ "mov %0, x0" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "x21" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[8]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "ldr x0, [%1, #8] \n\t" \ "ldr x1, [%1, #16] \n\t" \ "ldr x2, [%1, #24] \n\t" \ "ldr x3, [%1, #32] \n\t" \ "ldr x4, [%1, #40] \n\t" \ "ldr x5, [%1, #48] \n\t" \ "ldr x6, [%1, #56] \n\t" \ "ldr x8, [%1] \n\t" /* target->x8 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_X8 \ VALGRIND_RESTORE_STACK \ "mov %0, x0" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "x21" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[9]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "ldr x0, [%1, #8] \n\t" \ "ldr x1, [%1, #16] \n\t" \ "ldr x2, [%1, #24] \n\t" \ "ldr x3, [%1, #32] \n\t" \ "ldr x4, [%1, #40] \n\t" \ "ldr x5, [%1, #48] \n\t" \ "ldr x6, [%1, #56] \n\t" \ "ldr x7, [%1, #64] \n\t" \ "ldr x8, [%1] \n\t" /* target->x8 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_X8 \ VALGRIND_RESTORE_STACK \ "mov %0, x0" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "x21" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[10]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ _argvec[9] = (unsigned long)(arg9); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "sub sp, sp, #0x20 \n\t" \ "ldr x0, [%1, #8] \n\t" \ "ldr x1, [%1, #16] \n\t" \ "ldr x2, [%1, #24] \n\t" \ "ldr x3, [%1, #32] \n\t" \ "ldr x4, [%1, #40] \n\t" \ "ldr x5, [%1, #48] \n\t" \ "ldr x6, [%1, #56] \n\t" \ "ldr x7, [%1, #64] \n\t" \ "ldr x8, [%1, #72] \n\t" \ "str x8, [sp, #0] \n\t" \ "ldr x8, [%1] \n\t" /* target->x8 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_X8 \ VALGRIND_RESTORE_STACK \ "mov %0, x0" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "x21" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9,arg10) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[11]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ _argvec[9] = (unsigned long)(arg9); \ _argvec[10] = (unsigned long)(arg10); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "sub sp, sp, #0x20 \n\t" \ "ldr x0, [%1, #8] \n\t" \ "ldr x1, [%1, #16] \n\t" \ "ldr x2, [%1, #24] \n\t" \ "ldr x3, [%1, #32] \n\t" \ "ldr x4, [%1, #40] \n\t" \ "ldr x5, [%1, #48] \n\t" \ "ldr x6, [%1, #56] \n\t" \ "ldr x7, [%1, #64] \n\t" \ "ldr x8, [%1, #72] \n\t" \ "str x8, [sp, #0] \n\t" \ "ldr x8, [%1, #80] \n\t" \ "str x8, [sp, #8] \n\t" \ "ldr x8, [%1] \n\t" /* target->x8 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_X8 \ VALGRIND_RESTORE_STACK \ "mov %0, x0" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "x21" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9,arg10,arg11) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[12]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ _argvec[9] = (unsigned long)(arg9); \ _argvec[10] = (unsigned long)(arg10); \ _argvec[11] = (unsigned long)(arg11); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "sub sp, sp, #0x30 \n\t" \ "ldr x0, [%1, #8] \n\t" \ "ldr x1, [%1, #16] \n\t" \ "ldr x2, [%1, #24] \n\t" \ "ldr x3, [%1, #32] \n\t" \ "ldr x4, [%1, #40] \n\t" \ "ldr x5, [%1, #48] \n\t" \ "ldr x6, [%1, #56] \n\t" \ "ldr x7, [%1, #64] \n\t" \ "ldr x8, [%1, #72] \n\t" \ "str x8, [sp, #0] \n\t" \ "ldr x8, [%1, #80] \n\t" \ "str x8, [sp, #8] \n\t" \ "ldr x8, [%1, #88] \n\t" \ "str x8, [sp, #16] \n\t" \ "ldr x8, [%1] \n\t" /* target->x8 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_X8 \ VALGRIND_RESTORE_STACK \ "mov %0, x0" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "x21" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9,arg10,arg11, \ arg12) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[13]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ _argvec[9] = (unsigned long)(arg9); \ _argvec[10] = (unsigned long)(arg10); \ _argvec[11] = (unsigned long)(arg11); \ _argvec[12] = (unsigned long)(arg12); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "sub sp, sp, #0x30 \n\t" \ "ldr x0, [%1, #8] \n\t" \ "ldr x1, [%1, #16] \n\t" \ "ldr x2, [%1, #24] \n\t" \ "ldr x3, [%1, #32] \n\t" \ "ldr x4, [%1, #40] \n\t" \ "ldr x5, [%1, #48] \n\t" \ "ldr x6, [%1, #56] \n\t" \ "ldr x7, [%1, #64] \n\t" \ "ldr x8, [%1, #72] \n\t" \ "str x8, [sp, #0] \n\t" \ "ldr x8, [%1, #80] \n\t" \ "str x8, [sp, #8] \n\t" \ "ldr x8, [%1, #88] \n\t" \ "str x8, [sp, #16] \n\t" \ "ldr x8, [%1, #96] \n\t" \ "str x8, [sp, #24] \n\t" \ "ldr x8, [%1] \n\t" /* target->x8 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_X8 \ VALGRIND_RESTORE_STACK \ "mov %0, x0" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "x21" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #endif /* PLAT_arm64_linux */ /* ------------------------- s390x-linux ------------------------- */ #if defined(PLAT_s390x_linux) /* Similar workaround as amd64 (see above), but we use r11 as frame pointer and save the old r11 in r7. r11 might be used for argvec, therefore we copy argvec in r1 since r1 is clobbered after the call anyway. */ #if defined(__GNUC__) && defined(__GCC_HAVE_DWARF2_CFI_ASM) # define __FRAME_POINTER \ ,"d"(__builtin_dwarf_cfa()) # define VALGRIND_CFI_PROLOGUE \ ".cfi_remember_state\n\t" \ "lgr 1,%1\n\t" /* copy the argvec pointer in r1 */ \ "lgr 7,11\n\t" \ "lgr 11,%2\n\t" \ ".cfi_def_cfa r11, 0\n\t" # define VALGRIND_CFI_EPILOGUE \ "lgr 11, 7\n\t" \ ".cfi_restore_state\n\t" #else # define __FRAME_POINTER # define VALGRIND_CFI_PROLOGUE \ "lgr 1,%1\n\t" # define VALGRIND_CFI_EPILOGUE #endif /* Nb: On s390 the stack pointer is properly aligned *at all times* according to the s390 GCC maintainer. (The ABI specification is not precise in this regard.) Therefore, VALGRIND_ALIGN_STACK and VALGRIND_RESTORE_STACK are not defined here. */ /* These regs are trashed by the hidden call. Note that we overwrite r14 in s390_irgen_noredir (VEX/priv/guest_s390_irgen.c) to give the function a proper return address. All others are ABI defined call clobbers. */ #if defined(__VX__) || defined(__S390_VX__) #define __CALLER_SAVED_REGS "0", "1", "2", "3", "4", "5", "14", \ "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", \ "v8", "v9", "v10", "v11", "v12", "v13", "v14", "v15", \ "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23", \ "v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31" #else #define __CALLER_SAVED_REGS "0", "1", "2", "3", "4", "5", "14", \ "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7" #endif /* Nb: Although r11 is modified in the asm snippets below (inside VALGRIND_CFI_PROLOGUE) it is not listed in the clobber section, for two reasons: (1) r11 is restored in VALGRIND_CFI_EPILOGUE, so effectively it is not modified (2) GCC will complain that r11 cannot appear inside a clobber section, when compiled with -O -fno-omit-frame-pointer */ #define CALL_FN_W_v(lval, orig) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[1]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ __asm__ volatile( \ VALGRIND_CFI_PROLOGUE \ "aghi 15,-160\n\t" \ "lg 1, 0(1)\n\t" /* target->r1 */ \ VALGRIND_CALL_NOREDIR_R1 \ "aghi 15,160\n\t" \ VALGRIND_CFI_EPILOGUE \ "lgr %0, 2\n\t" \ : /*out*/ "=d" (_res) \ : /*in*/ "d" (&_argvec[0]) __FRAME_POINTER \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"7" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) /* The call abi has the arguments in r2-r6 and stack */ #define CALL_FN_W_W(lval, orig, arg1) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[2]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)arg1; \ __asm__ volatile( \ VALGRIND_CFI_PROLOGUE \ "aghi 15,-160\n\t" \ "lg 2, 8(1)\n\t" \ "lg 1, 0(1)\n\t" \ VALGRIND_CALL_NOREDIR_R1 \ "aghi 15,160\n\t" \ VALGRIND_CFI_EPILOGUE \ "lgr %0, 2\n\t" \ : /*out*/ "=d" (_res) \ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"7" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WW(lval, orig, arg1, arg2) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)arg1; \ _argvec[2] = (unsigned long)arg2; \ __asm__ volatile( \ VALGRIND_CFI_PROLOGUE \ "aghi 15,-160\n\t" \ "lg 2, 8(1)\n\t" \ "lg 3,16(1)\n\t" \ "lg 1, 0(1)\n\t" \ VALGRIND_CALL_NOREDIR_R1 \ "aghi 15,160\n\t" \ VALGRIND_CFI_EPILOGUE \ "lgr %0, 2\n\t" \ : /*out*/ "=d" (_res) \ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"7" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WWW(lval, orig, arg1, arg2, arg3) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[4]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)arg1; \ _argvec[2] = (unsigned long)arg2; \ _argvec[3] = (unsigned long)arg3; \ __asm__ volatile( \ VALGRIND_CFI_PROLOGUE \ "aghi 15,-160\n\t" \ "lg 2, 8(1)\n\t" \ "lg 3,16(1)\n\t" \ "lg 4,24(1)\n\t" \ "lg 1, 0(1)\n\t" \ VALGRIND_CALL_NOREDIR_R1 \ "aghi 15,160\n\t" \ VALGRIND_CFI_EPILOGUE \ "lgr %0, 2\n\t" \ : /*out*/ "=d" (_res) \ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"7" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WWWW(lval, orig, arg1, arg2, arg3, arg4) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[5]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)arg1; \ _argvec[2] = (unsigned long)arg2; \ _argvec[3] = (unsigned long)arg3; \ _argvec[4] = (unsigned long)arg4; \ __asm__ volatile( \ VALGRIND_CFI_PROLOGUE \ "aghi 15,-160\n\t" \ "lg 2, 8(1)\n\t" \ "lg 3,16(1)\n\t" \ "lg 4,24(1)\n\t" \ "lg 5,32(1)\n\t" \ "lg 1, 0(1)\n\t" \ VALGRIND_CALL_NOREDIR_R1 \ "aghi 15,160\n\t" \ VALGRIND_CFI_EPILOGUE \ "lgr %0, 2\n\t" \ : /*out*/ "=d" (_res) \ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"7" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_5W(lval, orig, arg1, arg2, arg3, arg4, arg5) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[6]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)arg1; \ _argvec[2] = (unsigned long)arg2; \ _argvec[3] = (unsigned long)arg3; \ _argvec[4] = (unsigned long)arg4; \ _argvec[5] = (unsigned long)arg5; \ __asm__ volatile( \ VALGRIND_CFI_PROLOGUE \ "aghi 15,-160\n\t" \ "lg 2, 8(1)\n\t" \ "lg 3,16(1)\n\t" \ "lg 4,24(1)\n\t" \ "lg 5,32(1)\n\t" \ "lg 6,40(1)\n\t" \ "lg 1, 0(1)\n\t" \ VALGRIND_CALL_NOREDIR_R1 \ "aghi 15,160\n\t" \ VALGRIND_CFI_EPILOGUE \ "lgr %0, 2\n\t" \ : /*out*/ "=d" (_res) \ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"6","7" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_6W(lval, orig, arg1, arg2, arg3, arg4, arg5, \ arg6) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[7]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)arg1; \ _argvec[2] = (unsigned long)arg2; \ _argvec[3] = (unsigned long)arg3; \ _argvec[4] = (unsigned long)arg4; \ _argvec[5] = (unsigned long)arg5; \ _argvec[6] = (unsigned long)arg6; \ __asm__ volatile( \ VALGRIND_CFI_PROLOGUE \ "aghi 15,-168\n\t" \ "lg 2, 8(1)\n\t" \ "lg 3,16(1)\n\t" \ "lg 4,24(1)\n\t" \ "lg 5,32(1)\n\t" \ "lg 6,40(1)\n\t" \ "mvc 160(8,15), 48(1)\n\t" \ "lg 1, 0(1)\n\t" \ VALGRIND_CALL_NOREDIR_R1 \ "aghi 15,168\n\t" \ VALGRIND_CFI_EPILOGUE \ "lgr %0, 2\n\t" \ : /*out*/ "=d" (_res) \ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"6","7" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_7W(lval, orig, arg1, arg2, arg3, arg4, arg5, \ arg6, arg7) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[8]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)arg1; \ _argvec[2] = (unsigned long)arg2; \ _argvec[3] = (unsigned long)arg3; \ _argvec[4] = (unsigned long)arg4; \ _argvec[5] = (unsigned long)arg5; \ _argvec[6] = (unsigned long)arg6; \ _argvec[7] = (unsigned long)arg7; \ __asm__ volatile( \ VALGRIND_CFI_PROLOGUE \ "aghi 15,-176\n\t" \ "lg 2, 8(1)\n\t" \ "lg 3,16(1)\n\t" \ "lg 4,24(1)\n\t" \ "lg 5,32(1)\n\t" \ "lg 6,40(1)\n\t" \ "mvc 160(8,15), 48(1)\n\t" \ "mvc 168(8,15), 56(1)\n\t" \ "lg 1, 0(1)\n\t" \ VALGRIND_CALL_NOREDIR_R1 \ "aghi 15,176\n\t" \ VALGRIND_CFI_EPILOGUE \ "lgr %0, 2\n\t" \ : /*out*/ "=d" (_res) \ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"6","7" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_8W(lval, orig, arg1, arg2, arg3, arg4, arg5, \ arg6, arg7 ,arg8) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[9]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)arg1; \ _argvec[2] = (unsigned long)arg2; \ _argvec[3] = (unsigned long)arg3; \ _argvec[4] = (unsigned long)arg4; \ _argvec[5] = (unsigned long)arg5; \ _argvec[6] = (unsigned long)arg6; \ _argvec[7] = (unsigned long)arg7; \ _argvec[8] = (unsigned long)arg8; \ __asm__ volatile( \ VALGRIND_CFI_PROLOGUE \ "aghi 15,-184\n\t" \ "lg 2, 8(1)\n\t" \ "lg 3,16(1)\n\t" \ "lg 4,24(1)\n\t" \ "lg 5,32(1)\n\t" \ "lg 6,40(1)\n\t" \ "mvc 160(8,15), 48(1)\n\t" \ "mvc 168(8,15), 56(1)\n\t" \ "mvc 176(8,15), 64(1)\n\t" \ "lg 1, 0(1)\n\t" \ VALGRIND_CALL_NOREDIR_R1 \ "aghi 15,184\n\t" \ VALGRIND_CFI_EPILOGUE \ "lgr %0, 2\n\t" \ : /*out*/ "=d" (_res) \ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"6","7" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_9W(lval, orig, arg1, arg2, arg3, arg4, arg5, \ arg6, arg7 ,arg8, arg9) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[10]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)arg1; \ _argvec[2] = (unsigned long)arg2; \ _argvec[3] = (unsigned long)arg3; \ _argvec[4] = (unsigned long)arg4; \ _argvec[5] = (unsigned long)arg5; \ _argvec[6] = (unsigned long)arg6; \ _argvec[7] = (unsigned long)arg7; \ _argvec[8] = (unsigned long)arg8; \ _argvec[9] = (unsigned long)arg9; \ __asm__ volatile( \ VALGRIND_CFI_PROLOGUE \ "aghi 15,-192\n\t" \ "lg 2, 8(1)\n\t" \ "lg 3,16(1)\n\t" \ "lg 4,24(1)\n\t" \ "lg 5,32(1)\n\t" \ "lg 6,40(1)\n\t" \ "mvc 160(8,15), 48(1)\n\t" \ "mvc 168(8,15), 56(1)\n\t" \ "mvc 176(8,15), 64(1)\n\t" \ "mvc 184(8,15), 72(1)\n\t" \ "lg 1, 0(1)\n\t" \ VALGRIND_CALL_NOREDIR_R1 \ "aghi 15,192\n\t" \ VALGRIND_CFI_EPILOGUE \ "lgr %0, 2\n\t" \ : /*out*/ "=d" (_res) \ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"6","7" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_10W(lval, orig, arg1, arg2, arg3, arg4, arg5, \ arg6, arg7 ,arg8, arg9, arg10) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[11]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)arg1; \ _argvec[2] = (unsigned long)arg2; \ _argvec[3] = (unsigned long)arg3; \ _argvec[4] = (unsigned long)arg4; \ _argvec[5] = (unsigned long)arg5; \ _argvec[6] = (unsigned long)arg6; \ _argvec[7] = (unsigned long)arg7; \ _argvec[8] = (unsigned long)arg8; \ _argvec[9] = (unsigned long)arg9; \ _argvec[10] = (unsigned long)arg10; \ __asm__ volatile( \ VALGRIND_CFI_PROLOGUE \ "aghi 15,-200\n\t" \ "lg 2, 8(1)\n\t" \ "lg 3,16(1)\n\t" \ "lg 4,24(1)\n\t" \ "lg 5,32(1)\n\t" \ "lg 6,40(1)\n\t" \ "mvc 160(8,15), 48(1)\n\t" \ "mvc 168(8,15), 56(1)\n\t" \ "mvc 176(8,15), 64(1)\n\t" \ "mvc 184(8,15), 72(1)\n\t" \ "mvc 192(8,15), 80(1)\n\t" \ "lg 1, 0(1)\n\t" \ VALGRIND_CALL_NOREDIR_R1 \ "aghi 15,200\n\t" \ VALGRIND_CFI_EPILOGUE \ "lgr %0, 2\n\t" \ : /*out*/ "=d" (_res) \ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"6","7" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_11W(lval, orig, arg1, arg2, arg3, arg4, arg5, \ arg6, arg7 ,arg8, arg9, arg10, arg11) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[12]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)arg1; \ _argvec[2] = (unsigned long)arg2; \ _argvec[3] = (unsigned long)arg3; \ _argvec[4] = (unsigned long)arg4; \ _argvec[5] = (unsigned long)arg5; \ _argvec[6] = (unsigned long)arg6; \ _argvec[7] = (unsigned long)arg7; \ _argvec[8] = (unsigned long)arg8; \ _argvec[9] = (unsigned long)arg9; \ _argvec[10] = (unsigned long)arg10; \ _argvec[11] = (unsigned long)arg11; \ __asm__ volatile( \ VALGRIND_CFI_PROLOGUE \ "aghi 15,-208\n\t" \ "lg 2, 8(1)\n\t" \ "lg 3,16(1)\n\t" \ "lg 4,24(1)\n\t" \ "lg 5,32(1)\n\t" \ "lg 6,40(1)\n\t" \ "mvc 160(8,15), 48(1)\n\t" \ "mvc 168(8,15), 56(1)\n\t" \ "mvc 176(8,15), 64(1)\n\t" \ "mvc 184(8,15), 72(1)\n\t" \ "mvc 192(8,15), 80(1)\n\t" \ "mvc 200(8,15), 88(1)\n\t" \ "lg 1, 0(1)\n\t" \ VALGRIND_CALL_NOREDIR_R1 \ "aghi 15,208\n\t" \ VALGRIND_CFI_EPILOGUE \ "lgr %0, 2\n\t" \ : /*out*/ "=d" (_res) \ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"6","7" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_12W(lval, orig, arg1, arg2, arg3, arg4, arg5, \ arg6, arg7 ,arg8, arg9, arg10, arg11, arg12)\ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[13]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)arg1; \ _argvec[2] = (unsigned long)arg2; \ _argvec[3] = (unsigned long)arg3; \ _argvec[4] = (unsigned long)arg4; \ _argvec[5] = (unsigned long)arg5; \ _argvec[6] = (unsigned long)arg6; \ _argvec[7] = (unsigned long)arg7; \ _argvec[8] = (unsigned long)arg8; \ _argvec[9] = (unsigned long)arg9; \ _argvec[10] = (unsigned long)arg10; \ _argvec[11] = (unsigned long)arg11; \ _argvec[12] = (unsigned long)arg12; \ __asm__ volatile( \ VALGRIND_CFI_PROLOGUE \ "aghi 15,-216\n\t" \ "lg 2, 8(1)\n\t" \ "lg 3,16(1)\n\t" \ "lg 4,24(1)\n\t" \ "lg 5,32(1)\n\t" \ "lg 6,40(1)\n\t" \ "mvc 160(8,15), 48(1)\n\t" \ "mvc 168(8,15), 56(1)\n\t" \ "mvc 176(8,15), 64(1)\n\t" \ "mvc 184(8,15), 72(1)\n\t" \ "mvc 192(8,15), 80(1)\n\t" \ "mvc 200(8,15), 88(1)\n\t" \ "mvc 208(8,15), 96(1)\n\t" \ "lg 1, 0(1)\n\t" \ VALGRIND_CALL_NOREDIR_R1 \ "aghi 15,216\n\t" \ VALGRIND_CFI_EPILOGUE \ "lgr %0, 2\n\t" \ : /*out*/ "=d" (_res) \ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"6","7" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #endif /* PLAT_s390x_linux */ /* ------------------------- mips32-linux ----------------------- */ #if defined(PLAT_mips32_linux) /* These regs are trashed by the hidden call. */ #define __CALLER_SAVED_REGS "$2", "$3", "$4", "$5", "$6", \ "$7", "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15", "$24", \ "$25", "$31" /* These CALL_FN_ macros assume that on mips-linux, sizeof(unsigned long) == 4. */ #define CALL_FN_W_v(lval, orig) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[1]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ __asm__ volatile( \ "subu $29, $29, 8 \n\t" \ "sw $28, 0($29) \n\t" \ "sw $31, 4($29) \n\t" \ "subu $29, $29, 16 \n\t" \ "lw $25, 0(%1) \n\t" /* target->t9 */ \ VALGRIND_CALL_NOREDIR_T9 \ "addu $29, $29, 16\n\t" \ "lw $28, 0($29) \n\t" \ "lw $31, 4($29) \n\t" \ "addu $29, $29, 8 \n\t" \ "move %0, $2\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_W(lval, orig, arg1) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[2]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ __asm__ volatile( \ "subu $29, $29, 8 \n\t" \ "sw $28, 0($29) \n\t" \ "sw $31, 4($29) \n\t" \ "subu $29, $29, 16 \n\t" \ "lw $4, 4(%1) \n\t" /* arg1*/ \ "lw $25, 0(%1) \n\t" /* target->t9 */ \ VALGRIND_CALL_NOREDIR_T9 \ "addu $29, $29, 16 \n\t" \ "lw $28, 0($29) \n\t" \ "lw $31, 4($29) \n\t" \ "addu $29, $29, 8 \n\t" \ "move %0, $2\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WW(lval, orig, arg1,arg2) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ __asm__ volatile( \ "subu $29, $29, 8 \n\t" \ "sw $28, 0($29) \n\t" \ "sw $31, 4($29) \n\t" \ "subu $29, $29, 16 \n\t" \ "lw $4, 4(%1) \n\t" \ "lw $5, 8(%1) \n\t" \ "lw $25, 0(%1) \n\t" /* target->t9 */ \ VALGRIND_CALL_NOREDIR_T9 \ "addu $29, $29, 16 \n\t" \ "lw $28, 0($29) \n\t" \ "lw $31, 4($29) \n\t" \ "addu $29, $29, 8 \n\t" \ "move %0, $2\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[4]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ __asm__ volatile( \ "subu $29, $29, 8 \n\t" \ "sw $28, 0($29) \n\t" \ "sw $31, 4($29) \n\t" \ "subu $29, $29, 16 \n\t" \ "lw $4, 4(%1) \n\t" \ "lw $5, 8(%1) \n\t" \ "lw $6, 12(%1) \n\t" \ "lw $25, 0(%1) \n\t" /* target->t9 */ \ VALGRIND_CALL_NOREDIR_T9 \ "addu $29, $29, 16 \n\t" \ "lw $28, 0($29) \n\t" \ "lw $31, 4($29) \n\t" \ "addu $29, $29, 8 \n\t" \ "move %0, $2\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[5]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ __asm__ volatile( \ "subu $29, $29, 8 \n\t" \ "sw $28, 0($29) \n\t" \ "sw $31, 4($29) \n\t" \ "subu $29, $29, 16 \n\t" \ "lw $4, 4(%1) \n\t" \ "lw $5, 8(%1) \n\t" \ "lw $6, 12(%1) \n\t" \ "lw $7, 16(%1) \n\t" \ "lw $25, 0(%1) \n\t" /* target->t9 */ \ VALGRIND_CALL_NOREDIR_T9 \ "addu $29, $29, 16 \n\t" \ "lw $28, 0($29) \n\t" \ "lw $31, 4($29) \n\t" \ "addu $29, $29, 8 \n\t" \ "move %0, $2\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[6]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ __asm__ volatile( \ "subu $29, $29, 8 \n\t" \ "sw $28, 0($29) \n\t" \ "sw $31, 4($29) \n\t" \ "lw $4, 20(%1) \n\t" \ "subu $29, $29, 24\n\t" \ "sw $4, 16($29) \n\t" \ "lw $4, 4(%1) \n\t" \ "lw $5, 8(%1) \n\t" \ "lw $6, 12(%1) \n\t" \ "lw $7, 16(%1) \n\t" \ "lw $25, 0(%1) \n\t" /* target->t9 */ \ VALGRIND_CALL_NOREDIR_T9 \ "addu $29, $29, 24 \n\t" \ "lw $28, 0($29) \n\t" \ "lw $31, 4($29) \n\t" \ "addu $29, $29, 8 \n\t" \ "move %0, $2\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[7]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ __asm__ volatile( \ "subu $29, $29, 8 \n\t" \ "sw $28, 0($29) \n\t" \ "sw $31, 4($29) \n\t" \ "lw $4, 20(%1) \n\t" \ "subu $29, $29, 32\n\t" \ "sw $4, 16($29) \n\t" \ "lw $4, 24(%1) \n\t" \ "nop\n\t" \ "sw $4, 20($29) \n\t" \ "lw $4, 4(%1) \n\t" \ "lw $5, 8(%1) \n\t" \ "lw $6, 12(%1) \n\t" \ "lw $7, 16(%1) \n\t" \ "lw $25, 0(%1) \n\t" /* target->t9 */ \ VALGRIND_CALL_NOREDIR_T9 \ "addu $29, $29, 32 \n\t" \ "lw $28, 0($29) \n\t" \ "lw $31, 4($29) \n\t" \ "addu $29, $29, 8 \n\t" \ "move %0, $2\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[8]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ __asm__ volatile( \ "subu $29, $29, 8 \n\t" \ "sw $28, 0($29) \n\t" \ "sw $31, 4($29) \n\t" \ "lw $4, 20(%1) \n\t" \ "subu $29, $29, 32\n\t" \ "sw $4, 16($29) \n\t" \ "lw $4, 24(%1) \n\t" \ "sw $4, 20($29) \n\t" \ "lw $4, 28(%1) \n\t" \ "sw $4, 24($29) \n\t" \ "lw $4, 4(%1) \n\t" \ "lw $5, 8(%1) \n\t" \ "lw $6, 12(%1) \n\t" \ "lw $7, 16(%1) \n\t" \ "lw $25, 0(%1) \n\t" /* target->t9 */ \ VALGRIND_CALL_NOREDIR_T9 \ "addu $29, $29, 32 \n\t" \ "lw $28, 0($29) \n\t" \ "lw $31, 4($29) \n\t" \ "addu $29, $29, 8 \n\t" \ "move %0, $2\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[9]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ __asm__ volatile( \ "subu $29, $29, 8 \n\t" \ "sw $28, 0($29) \n\t" \ "sw $31, 4($29) \n\t" \ "lw $4, 20(%1) \n\t" \ "subu $29, $29, 40\n\t" \ "sw $4, 16($29) \n\t" \ "lw $4, 24(%1) \n\t" \ "sw $4, 20($29) \n\t" \ "lw $4, 28(%1) \n\t" \ "sw $4, 24($29) \n\t" \ "lw $4, 32(%1) \n\t" \ "sw $4, 28($29) \n\t" \ "lw $4, 4(%1) \n\t" \ "lw $5, 8(%1) \n\t" \ "lw $6, 12(%1) \n\t" \ "lw $7, 16(%1) \n\t" \ "lw $25, 0(%1) \n\t" /* target->t9 */ \ VALGRIND_CALL_NOREDIR_T9 \ "addu $29, $29, 40 \n\t" \ "lw $28, 0($29) \n\t" \ "lw $31, 4($29) \n\t" \ "addu $29, $29, 8 \n\t" \ "move %0, $2\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[10]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ _argvec[9] = (unsigned long)(arg9); \ __asm__ volatile( \ "subu $29, $29, 8 \n\t" \ "sw $28, 0($29) \n\t" \ "sw $31, 4($29) \n\t" \ "lw $4, 20(%1) \n\t" \ "subu $29, $29, 40\n\t" \ "sw $4, 16($29) \n\t" \ "lw $4, 24(%1) \n\t" \ "sw $4, 20($29) \n\t" \ "lw $4, 28(%1) \n\t" \ "sw $4, 24($29) \n\t" \ "lw $4, 32(%1) \n\t" \ "sw $4, 28($29) \n\t" \ "lw $4, 36(%1) \n\t" \ "sw $4, 32($29) \n\t" \ "lw $4, 4(%1) \n\t" \ "lw $5, 8(%1) \n\t" \ "lw $6, 12(%1) \n\t" \ "lw $7, 16(%1) \n\t" \ "lw $25, 0(%1) \n\t" /* target->t9 */ \ VALGRIND_CALL_NOREDIR_T9 \ "addu $29, $29, 40 \n\t" \ "lw $28, 0($29) \n\t" \ "lw $31, 4($29) \n\t" \ "addu $29, $29, 8 \n\t" \ "move %0, $2\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9,arg10) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[11]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ _argvec[9] = (unsigned long)(arg9); \ _argvec[10] = (unsigned long)(arg10); \ __asm__ volatile( \ "subu $29, $29, 8 \n\t" \ "sw $28, 0($29) \n\t" \ "sw $31, 4($29) \n\t" \ "lw $4, 20(%1) \n\t" \ "subu $29, $29, 48\n\t" \ "sw $4, 16($29) \n\t" \ "lw $4, 24(%1) \n\t" \ "sw $4, 20($29) \n\t" \ "lw $4, 28(%1) \n\t" \ "sw $4, 24($29) \n\t" \ "lw $4, 32(%1) \n\t" \ "sw $4, 28($29) \n\t" \ "lw $4, 36(%1) \n\t" \ "sw $4, 32($29) \n\t" \ "lw $4, 40(%1) \n\t" \ "sw $4, 36($29) \n\t" \ "lw $4, 4(%1) \n\t" \ "lw $5, 8(%1) \n\t" \ "lw $6, 12(%1) \n\t" \ "lw $7, 16(%1) \n\t" \ "lw $25, 0(%1) \n\t" /* target->t9 */ \ VALGRIND_CALL_NOREDIR_T9 \ "addu $29, $29, 48 \n\t" \ "lw $28, 0($29) \n\t" \ "lw $31, 4($29) \n\t" \ "addu $29, $29, 8 \n\t" \ "move %0, $2\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5, \ arg6,arg7,arg8,arg9,arg10, \ arg11) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[12]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ _argvec[9] = (unsigned long)(arg9); \ _argvec[10] = (unsigned long)(arg10); \ _argvec[11] = (unsigned long)(arg11); \ __asm__ volatile( \ "subu $29, $29, 8 \n\t" \ "sw $28, 0($29) \n\t" \ "sw $31, 4($29) \n\t" \ "lw $4, 20(%1) \n\t" \ "subu $29, $29, 48\n\t" \ "sw $4, 16($29) \n\t" \ "lw $4, 24(%1) \n\t" \ "sw $4, 20($29) \n\t" \ "lw $4, 28(%1) \n\t" \ "sw $4, 24($29) \n\t" \ "lw $4, 32(%1) \n\t" \ "sw $4, 28($29) \n\t" \ "lw $4, 36(%1) \n\t" \ "sw $4, 32($29) \n\t" \ "lw $4, 40(%1) \n\t" \ "sw $4, 36($29) \n\t" \ "lw $4, 44(%1) \n\t" \ "sw $4, 40($29) \n\t" \ "lw $4, 4(%1) \n\t" \ "lw $5, 8(%1) \n\t" \ "lw $6, 12(%1) \n\t" \ "lw $7, 16(%1) \n\t" \ "lw $25, 0(%1) \n\t" /* target->t9 */ \ VALGRIND_CALL_NOREDIR_T9 \ "addu $29, $29, 48 \n\t" \ "lw $28, 0($29) \n\t" \ "lw $31, 4($29) \n\t" \ "addu $29, $29, 8 \n\t" \ "move %0, $2\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5, \ arg6,arg7,arg8,arg9,arg10, \ arg11,arg12) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[13]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ _argvec[9] = (unsigned long)(arg9); \ _argvec[10] = (unsigned long)(arg10); \ _argvec[11] = (unsigned long)(arg11); \ _argvec[12] = (unsigned long)(arg12); \ __asm__ volatile( \ "subu $29, $29, 8 \n\t" \ "sw $28, 0($29) \n\t" \ "sw $31, 4($29) \n\t" \ "lw $4, 20(%1) \n\t" \ "subu $29, $29, 56\n\t" \ "sw $4, 16($29) \n\t" \ "lw $4, 24(%1) \n\t" \ "sw $4, 20($29) \n\t" \ "lw $4, 28(%1) \n\t" \ "sw $4, 24($29) \n\t" \ "lw $4, 32(%1) \n\t" \ "sw $4, 28($29) \n\t" \ "lw $4, 36(%1) \n\t" \ "sw $4, 32($29) \n\t" \ "lw $4, 40(%1) \n\t" \ "sw $4, 36($29) \n\t" \ "lw $4, 44(%1) \n\t" \ "sw $4, 40($29) \n\t" \ "lw $4, 48(%1) \n\t" \ "sw $4, 44($29) \n\t" \ "lw $4, 4(%1) \n\t" \ "lw $5, 8(%1) \n\t" \ "lw $6, 12(%1) \n\t" \ "lw $7, 16(%1) \n\t" \ "lw $25, 0(%1) \n\t" /* target->t9 */ \ VALGRIND_CALL_NOREDIR_T9 \ "addu $29, $29, 56 \n\t" \ "lw $28, 0($29) \n\t" \ "lw $31, 4($29) \n\t" \ "addu $29, $29, 8 \n\t" \ "move %0, $2\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #endif /* PLAT_mips32_linux */ /* ------------------------- nanomips-linux -------------------- */ #if defined(PLAT_nanomips_linux) /* These regs are trashed by the hidden call. */ #define __CALLER_SAVED_REGS "$t4", "$t5", "$a0", "$a1", "$a2", \ "$a3", "$a4", "$a5", "$a6", "$a7", "$t0", "$t1", "$t2", "$t3", \ "$t8","$t9", "$at" /* These CALL_FN_ macros assume that on mips-linux, sizeof(unsigned long) == 4. */ #define CALL_FN_W_v(lval, orig) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[1]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ __asm__ volatile( \ "lw $t9, 0(%1)\n\t" \ VALGRIND_CALL_NOREDIR_T9 \ "move %0, $a0\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_W(lval, orig, arg1) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[2]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ __asm__ volatile( \ "lw $t9, 0(%1)\n\t" \ "lw $a0, 4(%1)\n\t" \ VALGRIND_CALL_NOREDIR_T9 \ "move %0, $a0\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WW(lval, orig, arg1,arg2) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ __asm__ volatile( \ "lw $t9, 0(%1)\n\t" \ "lw $a0, 4(%1)\n\t" \ "lw $a1, 8(%1)\n\t" \ VALGRIND_CALL_NOREDIR_T9 \ "move %0, $a0\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[4]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ __asm__ volatile( \ "lw $t9, 0(%1)\n\t" \ "lw $a0, 4(%1)\n\t" \ "lw $a1, 8(%1)\n\t" \ "lw $a2,12(%1)\n\t" \ VALGRIND_CALL_NOREDIR_T9 \ "move %0, $a0\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[5]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ __asm__ volatile( \ "lw $t9, 0(%1)\n\t" \ "lw $a0, 4(%1)\n\t" \ "lw $a1, 8(%1)\n\t" \ "lw $a2,12(%1)\n\t" \ "lw $a3,16(%1)\n\t" \ VALGRIND_CALL_NOREDIR_T9 \ "move %0, $a0\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[6]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ __asm__ volatile( \ "lw $t9, 0(%1)\n\t" \ "lw $a0, 4(%1)\n\t" \ "lw $a1, 8(%1)\n\t" \ "lw $a2,12(%1)\n\t" \ "lw $a3,16(%1)\n\t" \ "lw $a4,20(%1)\n\t" \ VALGRIND_CALL_NOREDIR_T9 \ "move %0, $a0\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[7]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ __asm__ volatile( \ "lw $t9, 0(%1)\n\t" \ "lw $a0, 4(%1)\n\t" \ "lw $a1, 8(%1)\n\t" \ "lw $a2,12(%1)\n\t" \ "lw $a3,16(%1)\n\t" \ "lw $a4,20(%1)\n\t" \ "lw $a5,24(%1)\n\t" \ VALGRIND_CALL_NOREDIR_T9 \ "move %0, $a0\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[8]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ __asm__ volatile( \ "lw $t9, 0(%1)\n\t" \ "lw $a0, 4(%1)\n\t" \ "lw $a1, 8(%1)\n\t" \ "lw $a2,12(%1)\n\t" \ "lw $a3,16(%1)\n\t" \ "lw $a4,20(%1)\n\t" \ "lw $a5,24(%1)\n\t" \ "lw $a6,28(%1)\n\t" \ VALGRIND_CALL_NOREDIR_T9 \ "move %0, $a0\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[9]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ __asm__ volatile( \ "lw $t9, 0(%1)\n\t" \ "lw $a0, 4(%1)\n\t" \ "lw $a1, 8(%1)\n\t" \ "lw $a2,12(%1)\n\t" \ "lw $a3,16(%1)\n\t" \ "lw $a4,20(%1)\n\t" \ "lw $a5,24(%1)\n\t" \ "lw $a6,28(%1)\n\t" \ "lw $a7,32(%1)\n\t" \ VALGRIND_CALL_NOREDIR_T9 \ "move %0, $a0\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[10]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ _argvec[9] = (unsigned long)(arg9); \ __asm__ volatile( \ "addiu $sp, $sp, -16 \n\t" \ "lw $t9,36(%1) \n\t" \ "sw $t9, 0($sp) \n\t" \ "lw $t9, 0(%1) \n\t" \ "lw $a0, 4(%1) \n\t" \ "lw $a1, 8(%1) \n\t" \ "lw $a2,12(%1) \n\t" \ "lw $a3,16(%1) \n\t" \ "lw $a4,20(%1) \n\t" \ "lw $a5,24(%1) \n\t" \ "lw $a6,28(%1) \n\t" \ "lw $a7,32(%1) \n\t" \ VALGRIND_CALL_NOREDIR_T9 \ "move %0, $a0 \n\t" \ "addiu $sp, $sp, 16 \n\t" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9,arg10) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[11]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ _argvec[9] = (unsigned long)(arg9); \ _argvec[10] = (unsigned long)(arg10); \ __asm__ volatile( \ "addiu $sp, $sp, -16 \n\t" \ "lw $t9,36(%1) \n\t" \ "sw $t9, 0($sp) \n\t" \ "lw $t9,40(%1) \n\t" \ "sw $t9, 4($sp) \n\t" \ "lw $t9, 0(%1) \n\t" \ "lw $a0, 4(%1) \n\t" \ "lw $a1, 8(%1) \n\t" \ "lw $a2,12(%1) \n\t" \ "lw $a3,16(%1) \n\t" \ "lw $a4,20(%1) \n\t" \ "lw $a5,24(%1) \n\t" \ "lw $a6,28(%1) \n\t" \ "lw $a7,32(%1) \n\t" \ VALGRIND_CALL_NOREDIR_T9 \ "move %0, $a0 \n\t" \ "addiu $sp, $sp, 16 \n\t" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5, \ arg6,arg7,arg8,arg9,arg10, \ arg11) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[12]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ _argvec[9] = (unsigned long)(arg9); \ _argvec[10] = (unsigned long)(arg10); \ _argvec[11] = (unsigned long)(arg11); \ __asm__ volatile( \ "addiu $sp, $sp, -16 \n\t" \ "lw $t9,36(%1) \n\t" \ "sw $t9, 0($sp) \n\t" \ "lw $t9,40(%1) \n\t" \ "sw $t9, 4($sp) \n\t" \ "lw $t9,44(%1) \n\t" \ "sw $t9, 8($sp) \n\t" \ "lw $t9, 0(%1) \n\t" \ "lw $a0, 4(%1) \n\t" \ "lw $a1, 8(%1) \n\t" \ "lw $a2,12(%1) \n\t" \ "lw $a3,16(%1) \n\t" \ "lw $a4,20(%1) \n\t" \ "lw $a5,24(%1) \n\t" \ "lw $a6,28(%1) \n\t" \ "lw $a7,32(%1) \n\t" \ VALGRIND_CALL_NOREDIR_T9 \ "move %0, $a0 \n\t" \ "addiu $sp, $sp, 16 \n\t" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5, \ arg6,arg7,arg8,arg9,arg10, \ arg11,arg12) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[13]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ _argvec[9] = (unsigned long)(arg9); \ _argvec[10] = (unsigned long)(arg10); \ _argvec[11] = (unsigned long)(arg11); \ _argvec[12] = (unsigned long)(arg12); \ __asm__ volatile( \ "addiu $sp, $sp, -16 \n\t" \ "lw $t9,36(%1) \n\t" \ "sw $t9, 0($sp) \n\t" \ "lw $t9,40(%1) \n\t" \ "sw $t9, 4($sp) \n\t" \ "lw $t9,44(%1) \n\t" \ "sw $t9, 8($sp) \n\t" \ "lw $t9,48(%1) \n\t" \ "sw $t9,12($sp) \n\t" \ "lw $t9, 0(%1) \n\t" \ "lw $a0, 4(%1) \n\t" \ "lw $a1, 8(%1) \n\t" \ "lw $a2,12(%1) \n\t" \ "lw $a3,16(%1) \n\t" \ "lw $a4,20(%1) \n\t" \ "lw $a5,24(%1) \n\t" \ "lw $a6,28(%1) \n\t" \ "lw $a7,32(%1) \n\t" \ VALGRIND_CALL_NOREDIR_T9 \ "move %0, $a0 \n\t" \ "addiu $sp, $sp, 16 \n\t" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #endif /* PLAT_nanomips_linux */ /* ------------------------- mips64-linux ------------------------- */ #if defined(PLAT_mips64_linux) /* These regs are trashed by the hidden call. */ #define __CALLER_SAVED_REGS "$2", "$3", "$4", "$5", "$6", \ "$7", "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15", "$24", \ "$25", "$31" /* These CALL_FN_ macros assume that on mips64-linux, sizeof(long long) == 8. */ #define MIPS64_LONG2REG_CAST(x) ((long long)(long)x) #define CALL_FN_W_v(lval, orig) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long long _argvec[1]; \ volatile unsigned long long _res; \ _argvec[0] = MIPS64_LONG2REG_CAST(_orig.nraddr); \ __asm__ volatile( \ "ld $25, 0(%1)\n\t" /* target->t9 */ \ VALGRIND_CALL_NOREDIR_T9 \ "move %0, $2\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) (long)_res; \ } while (0) #define CALL_FN_W_W(lval, orig, arg1) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long long _argvec[2]; \ volatile unsigned long long _res; \ _argvec[0] = MIPS64_LONG2REG_CAST(_orig.nraddr); \ _argvec[1] = MIPS64_LONG2REG_CAST(arg1); \ __asm__ volatile( \ "ld $4, 8(%1)\n\t" /* arg1*/ \ "ld $25, 0(%1)\n\t" /* target->t9 */ \ VALGRIND_CALL_NOREDIR_T9 \ "move %0, $2\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) (long)_res; \ } while (0) #define CALL_FN_W_WW(lval, orig, arg1,arg2) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long long _argvec[3]; \ volatile unsigned long long _res; \ _argvec[0] = _orig.nraddr; \ _argvec[1] = MIPS64_LONG2REG_CAST(arg1); \ _argvec[2] = MIPS64_LONG2REG_CAST(arg2); \ __asm__ volatile( \ "ld $4, 8(%1)\n\t" \ "ld $5, 16(%1)\n\t" \ "ld $25, 0(%1)\n\t" /* target->t9 */ \ VALGRIND_CALL_NOREDIR_T9 \ "move %0, $2\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) (long)_res; \ } while (0) #define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long long _argvec[4]; \ volatile unsigned long long _res; \ _argvec[0] = _orig.nraddr; \ _argvec[1] = MIPS64_LONG2REG_CAST(arg1); \ _argvec[2] = MIPS64_LONG2REG_CAST(arg2); \ _argvec[3] = MIPS64_LONG2REG_CAST(arg3); \ __asm__ volatile( \ "ld $4, 8(%1)\n\t" \ "ld $5, 16(%1)\n\t" \ "ld $6, 24(%1)\n\t" \ "ld $25, 0(%1)\n\t" /* target->t9 */ \ VALGRIND_CALL_NOREDIR_T9 \ "move %0, $2\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) (long)_res; \ } while (0) #define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long long _argvec[5]; \ volatile unsigned long long _res; \ _argvec[0] = MIPS64_LONG2REG_CAST(_orig.nraddr); \ _argvec[1] = MIPS64_LONG2REG_CAST(arg1); \ _argvec[2] = MIPS64_LONG2REG_CAST(arg2); \ _argvec[3] = MIPS64_LONG2REG_CAST(arg3); \ _argvec[4] = MIPS64_LONG2REG_CAST(arg4); \ __asm__ volatile( \ "ld $4, 8(%1)\n\t" \ "ld $5, 16(%1)\n\t" \ "ld $6, 24(%1)\n\t" \ "ld $7, 32(%1)\n\t" \ "ld $25, 0(%1)\n\t" /* target->t9 */ \ VALGRIND_CALL_NOREDIR_T9 \ "move %0, $2\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) (long)_res; \ } while (0) #define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long long _argvec[6]; \ volatile unsigned long long _res; \ _argvec[0] = MIPS64_LONG2REG_CAST(_orig.nraddr); \ _argvec[1] = MIPS64_LONG2REG_CAST(arg1); \ _argvec[2] = MIPS64_LONG2REG_CAST(arg2); \ _argvec[3] = MIPS64_LONG2REG_CAST(arg3); \ _argvec[4] = MIPS64_LONG2REG_CAST(arg4); \ _argvec[5] = MIPS64_LONG2REG_CAST(arg5); \ __asm__ volatile( \ "ld $4, 8(%1)\n\t" \ "ld $5, 16(%1)\n\t" \ "ld $6, 24(%1)\n\t" \ "ld $7, 32(%1)\n\t" \ "ld $8, 40(%1)\n\t" \ "ld $25, 0(%1)\n\t" /* target->t9 */ \ VALGRIND_CALL_NOREDIR_T9 \ "move %0, $2\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) (long)_res; \ } while (0) #define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long long _argvec[7]; \ volatile unsigned long long _res; \ _argvec[0] = MIPS64_LONG2REG_CAST(_orig.nraddr); \ _argvec[1] = MIPS64_LONG2REG_CAST(arg1); \ _argvec[2] = MIPS64_LONG2REG_CAST(arg2); \ _argvec[3] = MIPS64_LONG2REG_CAST(arg3); \ _argvec[4] = MIPS64_LONG2REG_CAST(arg4); \ _argvec[5] = MIPS64_LONG2REG_CAST(arg5); \ _argvec[6] = MIPS64_LONG2REG_CAST(arg6); \ __asm__ volatile( \ "ld $4, 8(%1)\n\t" \ "ld $5, 16(%1)\n\t" \ "ld $6, 24(%1)\n\t" \ "ld $7, 32(%1)\n\t" \ "ld $8, 40(%1)\n\t" \ "ld $9, 48(%1)\n\t" \ "ld $25, 0(%1)\n\t" /* target->t9 */ \ VALGRIND_CALL_NOREDIR_T9 \ "move %0, $2\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) (long)_res; \ } while (0) #define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long long _argvec[8]; \ volatile unsigned long long _res; \ _argvec[0] = MIPS64_LONG2REG_CAST(_orig.nraddr); \ _argvec[1] = MIPS64_LONG2REG_CAST(arg1); \ _argvec[2] = MIPS64_LONG2REG_CAST(arg2); \ _argvec[3] = MIPS64_LONG2REG_CAST(arg3); \ _argvec[4] = MIPS64_LONG2REG_CAST(arg4); \ _argvec[5] = MIPS64_LONG2REG_CAST(arg5); \ _argvec[6] = MIPS64_LONG2REG_CAST(arg6); \ _argvec[7] = MIPS64_LONG2REG_CAST(arg7); \ __asm__ volatile( \ "ld $4, 8(%1)\n\t" \ "ld $5, 16(%1)\n\t" \ "ld $6, 24(%1)\n\t" \ "ld $7, 32(%1)\n\t" \ "ld $8, 40(%1)\n\t" \ "ld $9, 48(%1)\n\t" \ "ld $10, 56(%1)\n\t" \ "ld $25, 0(%1) \n\t" /* target->t9 */ \ VALGRIND_CALL_NOREDIR_T9 \ "move %0, $2\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) (long)_res; \ } while (0) #define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long long _argvec[9]; \ volatile unsigned long long _res; \ _argvec[0] = MIPS64_LONG2REG_CAST(_orig.nraddr); \ _argvec[1] = MIPS64_LONG2REG_CAST(arg1); \ _argvec[2] = MIPS64_LONG2REG_CAST(arg2); \ _argvec[3] = MIPS64_LONG2REG_CAST(arg3); \ _argvec[4] = MIPS64_LONG2REG_CAST(arg4); \ _argvec[5] = MIPS64_LONG2REG_CAST(arg5); \ _argvec[6] = MIPS64_LONG2REG_CAST(arg6); \ _argvec[7] = MIPS64_LONG2REG_CAST(arg7); \ _argvec[8] = MIPS64_LONG2REG_CAST(arg8); \ __asm__ volatile( \ "ld $4, 8(%1)\n\t" \ "ld $5, 16(%1)\n\t" \ "ld $6, 24(%1)\n\t" \ "ld $7, 32(%1)\n\t" \ "ld $8, 40(%1)\n\t" \ "ld $9, 48(%1)\n\t" \ "ld $10, 56(%1)\n\t" \ "ld $11, 64(%1)\n\t" \ "ld $25, 0(%1) \n\t" /* target->t9 */ \ VALGRIND_CALL_NOREDIR_T9 \ "move %0, $2\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) (long)_res; \ } while (0) #define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long long _argvec[10]; \ volatile unsigned long long _res; \ _argvec[0] = MIPS64_LONG2REG_CAST(_orig.nraddr); \ _argvec[1] = MIPS64_LONG2REG_CAST(arg1); \ _argvec[2] = MIPS64_LONG2REG_CAST(arg2); \ _argvec[3] = MIPS64_LONG2REG_CAST(arg3); \ _argvec[4] = MIPS64_LONG2REG_CAST(arg4); \ _argvec[5] = MIPS64_LONG2REG_CAST(arg5); \ _argvec[6] = MIPS64_LONG2REG_CAST(arg6); \ _argvec[7] = MIPS64_LONG2REG_CAST(arg7); \ _argvec[8] = MIPS64_LONG2REG_CAST(arg8); \ _argvec[9] = MIPS64_LONG2REG_CAST(arg9); \ __asm__ volatile( \ "dsubu $29, $29, 8\n\t" \ "ld $4, 72(%1)\n\t" \ "sd $4, 0($29)\n\t" \ "ld $4, 8(%1)\n\t" \ "ld $5, 16(%1)\n\t" \ "ld $6, 24(%1)\n\t" \ "ld $7, 32(%1)\n\t" \ "ld $8, 40(%1)\n\t" \ "ld $9, 48(%1)\n\t" \ "ld $10, 56(%1)\n\t" \ "ld $11, 64(%1)\n\t" \ "ld $25, 0(%1)\n\t" /* target->t9 */ \ VALGRIND_CALL_NOREDIR_T9 \ "daddu $29, $29, 8\n\t" \ "move %0, $2\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) (long)_res; \ } while (0) #define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9,arg10) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long long _argvec[11]; \ volatile unsigned long long _res; \ _argvec[0] = MIPS64_LONG2REG_CAST(_orig.nraddr); \ _argvec[1] = MIPS64_LONG2REG_CAST(arg1); \ _argvec[2] = MIPS64_LONG2REG_CAST(arg2); \ _argvec[3] = MIPS64_LONG2REG_CAST(arg3); \ _argvec[4] = MIPS64_LONG2REG_CAST(arg4); \ _argvec[5] = MIPS64_LONG2REG_CAST(arg5); \ _argvec[6] = MIPS64_LONG2REG_CAST(arg6); \ _argvec[7] = MIPS64_LONG2REG_CAST(arg7); \ _argvec[8] = MIPS64_LONG2REG_CAST(arg8); \ _argvec[9] = MIPS64_LONG2REG_CAST(arg9); \ _argvec[10] = MIPS64_LONG2REG_CAST(arg10); \ __asm__ volatile( \ "dsubu $29, $29, 16\n\t" \ "ld $4, 72(%1)\n\t" \ "sd $4, 0($29)\n\t" \ "ld $4, 80(%1)\n\t" \ "sd $4, 8($29)\n\t" \ "ld $4, 8(%1)\n\t" \ "ld $5, 16(%1)\n\t" \ "ld $6, 24(%1)\n\t" \ "ld $7, 32(%1)\n\t" \ "ld $8, 40(%1)\n\t" \ "ld $9, 48(%1)\n\t" \ "ld $10, 56(%1)\n\t" \ "ld $11, 64(%1)\n\t" \ "ld $25, 0(%1)\n\t" /* target->t9 */ \ VALGRIND_CALL_NOREDIR_T9 \ "daddu $29, $29, 16\n\t" \ "move %0, $2\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) (long)_res; \ } while (0) #define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5, \ arg6,arg7,arg8,arg9,arg10, \ arg11) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long long _argvec[12]; \ volatile unsigned long long _res; \ _argvec[0] = MIPS64_LONG2REG_CAST(_orig.nraddr); \ _argvec[1] = MIPS64_LONG2REG_CAST(arg1); \ _argvec[2] = MIPS64_LONG2REG_CAST(arg2); \ _argvec[3] = MIPS64_LONG2REG_CAST(arg3); \ _argvec[4] = MIPS64_LONG2REG_CAST(arg4); \ _argvec[5] = MIPS64_LONG2REG_CAST(arg5); \ _argvec[6] = MIPS64_LONG2REG_CAST(arg6); \ _argvec[7] = MIPS64_LONG2REG_CAST(arg7); \ _argvec[8] = MIPS64_LONG2REG_CAST(arg8); \ _argvec[9] = MIPS64_LONG2REG_CAST(arg9); \ _argvec[10] = MIPS64_LONG2REG_CAST(arg10); \ _argvec[11] = MIPS64_LONG2REG_CAST(arg11); \ __asm__ volatile( \ "dsubu $29, $29, 24\n\t" \ "ld $4, 72(%1)\n\t" \ "sd $4, 0($29)\n\t" \ "ld $4, 80(%1)\n\t" \ "sd $4, 8($29)\n\t" \ "ld $4, 88(%1)\n\t" \ "sd $4, 16($29)\n\t" \ "ld $4, 8(%1)\n\t" \ "ld $5, 16(%1)\n\t" \ "ld $6, 24(%1)\n\t" \ "ld $7, 32(%1)\n\t" \ "ld $8, 40(%1)\n\t" \ "ld $9, 48(%1)\n\t" \ "ld $10, 56(%1)\n\t" \ "ld $11, 64(%1)\n\t" \ "ld $25, 0(%1)\n\t" /* target->t9 */ \ VALGRIND_CALL_NOREDIR_T9 \ "daddu $29, $29, 24\n\t" \ "move %0, $2\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) (long)_res; \ } while (0) #define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5, \ arg6,arg7,arg8,arg9,arg10, \ arg11,arg12) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long long _argvec[13]; \ volatile unsigned long long _res; \ _argvec[0] = MIPS64_LONG2REG_CAST(_orig.nraddr); \ _argvec[1] = MIPS64_LONG2REG_CAST(arg1); \ _argvec[2] = MIPS64_LONG2REG_CAST(arg2); \ _argvec[3] = MIPS64_LONG2REG_CAST(arg3); \ _argvec[4] = MIPS64_LONG2REG_CAST(arg4); \ _argvec[5] = MIPS64_LONG2REG_CAST(arg5); \ _argvec[6] = MIPS64_LONG2REG_CAST(arg6); \ _argvec[7] = MIPS64_LONG2REG_CAST(arg7); \ _argvec[8] = MIPS64_LONG2REG_CAST(arg8); \ _argvec[9] = MIPS64_LONG2REG_CAST(arg9); \ _argvec[10] = MIPS64_LONG2REG_CAST(arg10); \ _argvec[11] = MIPS64_LONG2REG_CAST(arg11); \ _argvec[12] = MIPS64_LONG2REG_CAST(arg12); \ __asm__ volatile( \ "dsubu $29, $29, 32\n\t" \ "ld $4, 72(%1)\n\t" \ "sd $4, 0($29)\n\t" \ "ld $4, 80(%1)\n\t" \ "sd $4, 8($29)\n\t" \ "ld $4, 88(%1)\n\t" \ "sd $4, 16($29)\n\t" \ "ld $4, 96(%1)\n\t" \ "sd $4, 24($29)\n\t" \ "ld $4, 8(%1)\n\t" \ "ld $5, 16(%1)\n\t" \ "ld $6, 24(%1)\n\t" \ "ld $7, 32(%1)\n\t" \ "ld $8, 40(%1)\n\t" \ "ld $9, 48(%1)\n\t" \ "ld $10, 56(%1)\n\t" \ "ld $11, 64(%1)\n\t" \ "ld $25, 0(%1)\n\t" /* target->t9 */ \ VALGRIND_CALL_NOREDIR_T9 \ "daddu $29, $29, 32\n\t" \ "move %0, $2\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) (long)_res; \ } while (0) #endif /* PLAT_mips64_linux */ /* ------------------------------------------------------------------ */ /* ARCHITECTURE INDEPENDENT MACROS for CLIENT REQUESTS. */ /* */ /* ------------------------------------------------------------------ */ /* Some request codes. There are many more of these, but most are not exposed to end-user view. These are the public ones, all of the form 0x1000 + small_number. Core ones are in the range 0x00000000--0x0000ffff. The non-public ones start at 0x2000. */ /* These macros are used by tools -- they must be public, but don't embed them into other programs. */ #define VG_USERREQ_TOOL_BASE(a,b) \ ((unsigned int)(((a)&0xff) << 24 | ((b)&0xff) << 16)) #define VG_IS_TOOL_USERREQ(a, b, v) \ (VG_USERREQ_TOOL_BASE(a,b) == ((v) & 0xffff0000)) /* !! ABIWARNING !! ABIWARNING !! ABIWARNING !! ABIWARNING !! This enum comprises an ABI exported by Valgrind to programs which use client requests. DO NOT CHANGE THE NUMERIC VALUES OF THESE ENTRIES, NOR DELETE ANY -- add new ones at the end of the most relevant group. */ typedef enum { VG_USERREQ__RUNNING_ON_VALGRIND = 0x1001, VG_USERREQ__DISCARD_TRANSLATIONS = 0x1002, /* These allow any function to be called from the simulated CPU but run on the real CPU. Nb: the first arg passed to the function is always the ThreadId of the running thread! So CLIENT_CALL0 actually requires a 1 arg function, etc. */ VG_USERREQ__CLIENT_CALL0 = 0x1101, VG_USERREQ__CLIENT_CALL1 = 0x1102, VG_USERREQ__CLIENT_CALL2 = 0x1103, VG_USERREQ__CLIENT_CALL3 = 0x1104, /* Can be useful in regression testing suites -- eg. can send Valgrind's output to /dev/null and still count errors. */ VG_USERREQ__COUNT_ERRORS = 0x1201, /* Allows the client program and/or gdbserver to execute a monitor command. */ VG_USERREQ__GDB_MONITOR_COMMAND = 0x1202, /* Allows the client program to change a dynamic command line option. */ VG_USERREQ__CLO_CHANGE = 0x1203, /* These are useful and can be interpreted by any tool that tracks malloc() et al, by using vg_replace_malloc.c. */ VG_USERREQ__MALLOCLIKE_BLOCK = 0x1301, VG_USERREQ__RESIZEINPLACE_BLOCK = 0x130b, VG_USERREQ__FREELIKE_BLOCK = 0x1302, /* Memory pool support. */ VG_USERREQ__CREATE_MEMPOOL = 0x1303, VG_USERREQ__DESTROY_MEMPOOL = 0x1304, VG_USERREQ__MEMPOOL_ALLOC = 0x1305, VG_USERREQ__MEMPOOL_FREE = 0x1306, VG_USERREQ__MEMPOOL_TRIM = 0x1307, VG_USERREQ__MOVE_MEMPOOL = 0x1308, VG_USERREQ__MEMPOOL_CHANGE = 0x1309, VG_USERREQ__MEMPOOL_EXISTS = 0x130a, /* Allow printfs to valgrind log. */ /* The first two pass the va_list argument by value, which assumes it is the same size as or smaller than a UWord, which generally isn't the case. Hence are deprecated. The second two pass the vargs by reference and so are immune to this problem. */ /* both :: char* fmt, va_list vargs (DEPRECATED) */ VG_USERREQ__PRINTF = 0x1401, VG_USERREQ__PRINTF_BACKTRACE = 0x1402, /* both :: char* fmt, va_list* vargs */ VG_USERREQ__PRINTF_VALIST_BY_REF = 0x1403, VG_USERREQ__PRINTF_BACKTRACE_VALIST_BY_REF = 0x1404, /* Stack support. */ VG_USERREQ__STACK_REGISTER = 0x1501, VG_USERREQ__STACK_DEREGISTER = 0x1502, VG_USERREQ__STACK_CHANGE = 0x1503, /* Wine support */ VG_USERREQ__LOAD_PDB_DEBUGINFO = 0x1601, /* Querying of debug info. */ VG_USERREQ__MAP_IP_TO_SRCLOC = 0x1701, /* Disable/enable error reporting level. Takes a single Word arg which is the delta to this thread's error disablement indicator. Hence 1 disables or further disables errors, and -1 moves back towards enablement. Other values are not allowed. */ VG_USERREQ__CHANGE_ERR_DISABLEMENT = 0x1801, /* Some requests used for Valgrind internal, such as self-test or self-hosting. */ /* Initialise IR injection */ VG_USERREQ__VEX_INIT_FOR_IRI = 0x1901, /* Used by Inner Valgrind to inform Outer Valgrind where to find the list of inner guest threads */ VG_USERREQ__INNER_THREADS = 0x1902 } Vg_ClientRequest; #if !defined(__GNUC__) # define __extension__ /* */ #endif /* Returns the number of Valgrinds this code is running under. That is, 0 if running natively, 1 if running under Valgrind, 2 if running under Valgrind which is running under another Valgrind, etc. */ #define RUNNING_ON_VALGRIND \ (unsigned)VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* if not */, \ VG_USERREQ__RUNNING_ON_VALGRIND, \ 0, 0, 0, 0, 0) \ /* Discard translation of code in the range [_qzz_addr .. _qzz_addr + _qzz_len - 1]. Useful if you are debugging a JITter or some such, since it provides a way to make sure valgrind will retranslate the invalidated area. Returns no value. */ #define VALGRIND_DISCARD_TRANSLATIONS(_qzz_addr,_qzz_len) \ VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__DISCARD_TRANSLATIONS, \ _qzz_addr, _qzz_len, 0, 0, 0) #define VALGRIND_INNER_THREADS(_qzz_addr) \ VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__INNER_THREADS, \ _qzz_addr, 0, 0, 0, 0) /* These requests are for getting Valgrind itself to print something. Possibly with a backtrace. This is a really ugly hack. The return value is the number of characters printed, excluding the "**** " part at the start and the backtrace (if present). */ #if defined(__GNUC__) || defined(__INTEL_COMPILER) && !defined(_MSC_VER) /* Modern GCC will optimize the static routine out if unused, and unused attribute will shut down warnings about it. */ static int VALGRIND_PRINTF(const char *format, ...) __attribute__((format(__printf__, 1, 2), __unused__)); #endif static int #if defined(_MSC_VER) __inline #endif VALGRIND_PRINTF(const char *format, ...) { #if defined(NVALGRIND) (void)format; return 0; #else /* NVALGRIND */ #if defined(_MSC_VER) || defined(__MINGW64__) uintptr_t _qzz_res; #else unsigned long _qzz_res; #endif va_list vargs; va_start(vargs, format); #if defined(_MSC_VER) || defined(__MINGW64__) _qzz_res = VALGRIND_DO_CLIENT_REQUEST_EXPR(0, VG_USERREQ__PRINTF_VALIST_BY_REF, (uintptr_t)format, (uintptr_t)&vargs, 0, 0, 0); #else _qzz_res = VALGRIND_DO_CLIENT_REQUEST_EXPR(0, VG_USERREQ__PRINTF_VALIST_BY_REF, (unsigned long)format, (unsigned long)&vargs, 0, 0, 0); #endif va_end(vargs); return (int)_qzz_res; #endif /* NVALGRIND */ } #if defined(__GNUC__) || defined(__INTEL_COMPILER) && !defined(_MSC_VER) static int VALGRIND_PRINTF_BACKTRACE(const char *format, ...) __attribute__((format(__printf__, 1, 2), __unused__)); #endif static int #if defined(_MSC_VER) __inline #endif VALGRIND_PRINTF_BACKTRACE(const char *format, ...) { #if defined(NVALGRIND) (void)format; return 0; #else /* NVALGRIND */ #if defined(_MSC_VER) || defined(__MINGW64__) uintptr_t _qzz_res; #else unsigned long _qzz_res; #endif va_list vargs; va_start(vargs, format); #if defined(_MSC_VER) || defined(__MINGW64__) _qzz_res = VALGRIND_DO_CLIENT_REQUEST_EXPR(0, VG_USERREQ__PRINTF_BACKTRACE_VALIST_BY_REF, (uintptr_t)format, (uintptr_t)&vargs, 0, 0, 0); #else _qzz_res = VALGRIND_DO_CLIENT_REQUEST_EXPR(0, VG_USERREQ__PRINTF_BACKTRACE_VALIST_BY_REF, (unsigned long)format, (unsigned long)&vargs, 0, 0, 0); #endif va_end(vargs); return (int)_qzz_res; #endif /* NVALGRIND */ } /* These requests allow control to move from the simulated CPU to the real CPU, calling an arbitrary function. Note that the current ThreadId is inserted as the first argument. So this call: VALGRIND_NON_SIMD_CALL2(f, arg1, arg2) requires f to have this signature: Word f(Word tid, Word arg1, Word arg2) where "Word" is a word-sized type. Note that these client requests are not entirely reliable. For example, if you call a function with them that subsequently calls printf(), there's a high chance Valgrind will crash. Generally, your prospects of these working are made higher if the called function does not refer to any global variables, and does not refer to any libc or other functions (printf et al). Any kind of entanglement with libc or dynamic linking is likely to have a bad outcome, for tricky reasons which we've grappled with a lot in the past. */ #define VALGRIND_NON_SIMD_CALL0(_qyy_fn) \ VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* default return */, \ VG_USERREQ__CLIENT_CALL0, \ _qyy_fn, \ 0, 0, 0, 0) #define VALGRIND_NON_SIMD_CALL1(_qyy_fn, _qyy_arg1) \ VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* default return */, \ VG_USERREQ__CLIENT_CALL1, \ _qyy_fn, \ _qyy_arg1, 0, 0, 0) #define VALGRIND_NON_SIMD_CALL2(_qyy_fn, _qyy_arg1, _qyy_arg2) \ VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* default return */, \ VG_USERREQ__CLIENT_CALL2, \ _qyy_fn, \ _qyy_arg1, _qyy_arg2, 0, 0) #define VALGRIND_NON_SIMD_CALL3(_qyy_fn, _qyy_arg1, _qyy_arg2, _qyy_arg3) \ VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* default return */, \ VG_USERREQ__CLIENT_CALL3, \ _qyy_fn, \ _qyy_arg1, _qyy_arg2, \ _qyy_arg3, 0) /* Counts the number of errors that have been recorded by a tool. Nb: the tool must record the errors with VG_(maybe_record_error)() or VG_(unique_error)() for them to be counted. */ #define VALGRIND_COUNT_ERRORS \ (unsigned)VALGRIND_DO_CLIENT_REQUEST_EXPR( \ 0 /* default return */, \ VG_USERREQ__COUNT_ERRORS, \ 0, 0, 0, 0, 0) /* Several Valgrind tools (Memcheck, Massif, Helgrind, DRD) rely on knowing when heap blocks are allocated in order to give accurate results. This happens automatically for the standard allocator functions such as malloc(), calloc(), realloc(), memalign(), new, new[], free(), delete, delete[], etc. But if your program uses a custom allocator, this doesn't automatically happen, and Valgrind will not do as well. For example, if you allocate superblocks with mmap() and then allocates chunks of the superblocks, all Valgrind's observations will be at the mmap() level and it won't know that the chunks should be considered separate entities. In Memcheck's case, that means you probably won't get heap block overrun detection (because there won't be redzones marked as unaddressable) and you definitely won't get any leak detection. The following client requests allow a custom allocator to be annotated so that it can be handled accurately by Valgrind. VALGRIND_MALLOCLIKE_BLOCK marks a region of memory as having been allocated by a malloc()-like function. For Memcheck (an illustrative case), this does two things: - It records that the block has been allocated. This means any addresses within the block mentioned in error messages will be identified as belonging to the block. It also means that if the block isn't freed it will be detected by the leak checker. - It marks the block as being addressable and undefined (if 'is_zeroed' is not set), or addressable and defined (if 'is_zeroed' is set). This controls how accesses to the block by the program are handled. 'addr' is the start of the usable block (ie. after any redzone), 'sizeB' is its size. 'rzB' is the redzone size if the allocator can apply redzones -- these are blocks of padding at the start and end of each block. Adding redzones is recommended as it makes it much more likely Valgrind will spot block overruns. `is_zeroed' indicates if the memory is zeroed (or filled with another predictable value), as is the case for calloc(). VALGRIND_MALLOCLIKE_BLOCK should be put immediately after the point where a heap block -- that will be used by the client program -- is allocated. It's best to put it at the outermost level of the allocator if possible; for example, if you have a function my_alloc() which calls internal_alloc(), and the client request is put inside internal_alloc(), stack traces relating to the heap block will contain entries for both my_alloc() and internal_alloc(), which is probably not what you want. For Memcheck users: if you use VALGRIND_MALLOCLIKE_BLOCK to carve out custom blocks from within a heap block, B, that has been allocated with malloc/calloc/new/etc, then block B will be *ignored* during leak-checking -- the custom blocks will take precedence. VALGRIND_FREELIKE_BLOCK is the partner to VALGRIND_MALLOCLIKE_BLOCK. For Memcheck, it does two things: - It records that the block has been deallocated. This assumes that the block was annotated as having been allocated via VALGRIND_MALLOCLIKE_BLOCK. Otherwise, an error will be issued. - It marks the block as being unaddressable. VALGRIND_FREELIKE_BLOCK should be put immediately after the point where a heap block is deallocated. VALGRIND_RESIZEINPLACE_BLOCK informs a tool about reallocation. For Memcheck, it does four things: - It records that the size of a block has been changed. This assumes that the block was annotated as having been allocated via VALGRIND_MALLOCLIKE_BLOCK. Otherwise, an error will be issued. - If the block shrunk, it marks the freed memory as being unaddressable. - If the block grew, it marks the new area as undefined and defines a red zone past the end of the new block. - The V-bits of the overlap between the old and the new block are preserved. VALGRIND_RESIZEINPLACE_BLOCK should be put after allocation of the new block and before deallocation of the old block. In many cases, these three client requests will not be enough to get your allocator working well with Memcheck. More specifically, if your allocator writes to freed blocks in any way then a VALGRIND_MAKE_MEM_UNDEFINED call will be necessary to mark the memory as addressable just before the zeroing occurs, otherwise you'll get a lot of invalid write errors. For example, you'll need to do this if your allocator recycles freed blocks, but it zeroes them before handing them back out (via VALGRIND_MALLOCLIKE_BLOCK). Alternatively, if your allocator reuses freed blocks for allocator-internal data structures, VALGRIND_MAKE_MEM_UNDEFINED calls will also be necessary. Really, what's happening is a blurring of the lines between the client program and the allocator... after VALGRIND_FREELIKE_BLOCK is called, the memory should be considered unaddressable to the client program, but the allocator knows more than the rest of the client program and so may be able to safely access it. Extra client requests are necessary for Valgrind to understand the distinction between the allocator and the rest of the program. Ignored if addr == 0. */ #define VALGRIND_MALLOCLIKE_BLOCK(addr, sizeB, rzB, is_zeroed) \ VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__MALLOCLIKE_BLOCK, \ addr, sizeB, rzB, is_zeroed, 0) /* See the comment for VALGRIND_MALLOCLIKE_BLOCK for details. Ignored if addr == 0. */ #define VALGRIND_RESIZEINPLACE_BLOCK(addr, oldSizeB, newSizeB, rzB) \ VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__RESIZEINPLACE_BLOCK, \ addr, oldSizeB, newSizeB, rzB, 0) /* See the comment for VALGRIND_MALLOCLIKE_BLOCK for details. Ignored if addr == 0. */ #define VALGRIND_FREELIKE_BLOCK(addr, rzB) \ VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__FREELIKE_BLOCK, \ addr, rzB, 0, 0, 0) /* Create a memory pool. */ #define VALGRIND_CREATE_MEMPOOL(pool, rzB, is_zeroed) \ VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__CREATE_MEMPOOL, \ pool, rzB, is_zeroed, 0, 0) /* Create a memory pool with some flags specifying extended behaviour. When flags is zero, the behaviour is identical to VALGRIND_CREATE_MEMPOOL. The flag VALGRIND_MEMPOOL_METAPOOL specifies that the pieces of memory associated with the pool using VALGRIND_MEMPOOL_ALLOC will be used by the application as superblocks to dole out MALLOC_LIKE blocks using VALGRIND_MALLOCLIKE_BLOCK. In other words, a meta pool is a "2 levels" pool : first level is the blocks described by VALGRIND_MEMPOOL_ALLOC. The second level blocks are described using VALGRIND_MALLOCLIKE_BLOCK. Note that the association between the pool and the second level blocks is implicit : second level blocks will be located inside first level blocks. It is necessary to use the VALGRIND_MEMPOOL_METAPOOL flag for such 2 levels pools, as otherwise valgrind will detect overlapping memory blocks, and will abort execution (e.g. during leak search). Such a meta pool can also be marked as an 'auto free' pool using the flag VALGRIND_MEMPOOL_AUTO_FREE, which must be OR-ed together with the VALGRIND_MEMPOOL_METAPOOL. For an 'auto free' pool, VALGRIND_MEMPOOL_FREE will automatically free the second level blocks that are contained inside the first level block freed with VALGRIND_MEMPOOL_FREE. In other words, calling VALGRIND_MEMPOOL_FREE will cause implicit calls to VALGRIND_FREELIKE_BLOCK for all the second level blocks included in the first level block. Note: it is an error to use the VALGRIND_MEMPOOL_AUTO_FREE flag without the VALGRIND_MEMPOOL_METAPOOL flag. */ #define VALGRIND_MEMPOOL_AUTO_FREE 1 #define VALGRIND_MEMPOOL_METAPOOL 2 #define VALGRIND_CREATE_MEMPOOL_EXT(pool, rzB, is_zeroed, flags) \ VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__CREATE_MEMPOOL, \ pool, rzB, is_zeroed, flags, 0) /* Destroy a memory pool. */ #define VALGRIND_DESTROY_MEMPOOL(pool) \ VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__DESTROY_MEMPOOL, \ pool, 0, 0, 0, 0) /* Associate a piece of memory with a memory pool. */ #define VALGRIND_MEMPOOL_ALLOC(pool, addr, size) \ VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__MEMPOOL_ALLOC, \ pool, addr, size, 0, 0) /* Disassociate a piece of memory from a memory pool. */ #define VALGRIND_MEMPOOL_FREE(pool, addr) \ VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__MEMPOOL_FREE, \ pool, addr, 0, 0, 0) /* Disassociate any pieces outside a particular range. */ #define VALGRIND_MEMPOOL_TRIM(pool, addr, size) \ VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__MEMPOOL_TRIM, \ pool, addr, size, 0, 0) /* Resize and/or move a piece associated with a memory pool. */ #define VALGRIND_MOVE_MEMPOOL(poolA, poolB) \ VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__MOVE_MEMPOOL, \ poolA, poolB, 0, 0, 0) /* Resize and/or move a piece associated with a memory pool. */ #define VALGRIND_MEMPOOL_CHANGE(pool, addrA, addrB, size) \ VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__MEMPOOL_CHANGE, \ pool, addrA, addrB, size, 0) /* Return 1 if a mempool exists, else 0. */ #define VALGRIND_MEMPOOL_EXISTS(pool) \ (unsigned)VALGRIND_DO_CLIENT_REQUEST_EXPR(0, \ VG_USERREQ__MEMPOOL_EXISTS, \ pool, 0, 0, 0, 0) /* Mark a piece of memory as being a stack. Returns a stack id. start is the lowest addressable stack byte, end is the highest addressable stack byte. */ #define VALGRIND_STACK_REGISTER(start, end) \ (unsigned)VALGRIND_DO_CLIENT_REQUEST_EXPR(0, \ VG_USERREQ__STACK_REGISTER, \ start, end, 0, 0, 0) /* Unmark the piece of memory associated with a stack id as being a stack. */ #define VALGRIND_STACK_DEREGISTER(id) \ VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__STACK_DEREGISTER, \ id, 0, 0, 0, 0) /* Change the start and end address of the stack id. start is the new lowest addressable stack byte, end is the new highest addressable stack byte. */ #define VALGRIND_STACK_CHANGE(id, start, end) \ VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__STACK_CHANGE, \ id, start, end, 0, 0) /* Load PDB debug info for Wine PE image_map. */ #define VALGRIND_LOAD_PDB_DEBUGINFO(fd, ptr, total_size, delta) \ VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__LOAD_PDB_DEBUGINFO, \ fd, ptr, total_size, delta, 0) /* Map a code address to a source file name and line number. buf64 must point to a 64-byte buffer in the caller's address space. The result will be dumped in there and is guaranteed to be zero terminated. If no info is found, the first byte is set to zero. */ #define VALGRIND_MAP_IP_TO_SRCLOC(addr, buf64) \ (unsigned)VALGRIND_DO_CLIENT_REQUEST_EXPR(0, \ VG_USERREQ__MAP_IP_TO_SRCLOC, \ addr, buf64, 0, 0, 0) /* Disable error reporting for this thread. Behaves in a stack like way, so you can safely call this multiple times provided that VALGRIND_ENABLE_ERROR_REPORTING is called the same number of times to re-enable reporting. The first call of this macro disables reporting. Subsequent calls have no effect except to increase the number of VALGRIND_ENABLE_ERROR_REPORTING calls needed to re-enable reporting. Child threads do not inherit this setting from their parents -- they are always created with reporting enabled. */ #define VALGRIND_DISABLE_ERROR_REPORTING \ VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__CHANGE_ERR_DISABLEMENT, \ 1, 0, 0, 0, 0) /* Re-enable error reporting, as per comments on VALGRIND_DISABLE_ERROR_REPORTING. */ #define VALGRIND_ENABLE_ERROR_REPORTING \ VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__CHANGE_ERR_DISABLEMENT, \ -1, 0, 0, 0, 0) /* Execute a monitor command from the client program. If a connection is opened with GDB, the output will be sent according to the output mode set for vgdb. If no connection is opened, output will go to the log output. Returns 1 if command not recognised, 0 otherwise. */ #define VALGRIND_MONITOR_COMMAND(command) \ VALGRIND_DO_CLIENT_REQUEST_EXPR(0, VG_USERREQ__GDB_MONITOR_COMMAND, \ command, 0, 0, 0, 0) /* Change the value of a dynamic command line option. Note that unknown or not dynamically changeable options will cause a warning message to be output. */ #define VALGRIND_CLO_CHANGE(option) \ VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__CLO_CHANGE, \ option, 0, 0, 0, 0) #undef PLAT_x86_darwin #undef PLAT_amd64_darwin #undef PLAT_x86_win32 #undef PLAT_amd64_win64 #undef PLAT_x86_linux #undef PLAT_amd64_linux #undef PLAT_ppc32_linux #undef PLAT_ppc64be_linux #undef PLAT_ppc64le_linux #undef PLAT_arm_linux #undef PLAT_s390x_linux #undef PLAT_mips32_linux #undef PLAT_mips64_linux #undef PLAT_nanomips_linux #undef PLAT_x86_solaris #undef PLAT_amd64_solaris #endif /* __VALGRIND_H */ librecast/src/000077500000000000000000000000001502456746400136325ustar00rootroot00000000000000librecast/src/Makefile.in000066400000000000000000000044121502456746400157000ustar00rootroot00000000000000# SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only # Copyright (c) 2017-2024 Brett Sheffield SHELL = /bin/sh VERSION := @PACKAGE_VERSION@ ABIVERS := @PACKAGE_ABIVERS@ ABIPARTS = $(subst ., ,$(ABIVERS)) SOMAJOR := $(word 1, $(ABIPARTS)) SOMINOR := $(word 2, $(ABIPARTS)) SOBUILD := $(word 3, $(ABIPARTS)) .SUFFIXES: .SUFFIXES: .c .o CFLAGS := -fPIC -I. -I../include $(CFLAGS) LIBNAME := librecast HEADERS = ../include/$(LIBNAME).h $(sort $(wildcard ../include/$(LIBNAME)/*.h)) INSTALL ?= install INSTALL_DATA := $(INSTALL) -m 644 LDCONFIG ?= ldconfig PREFIX = @prefix@ LIBDIR := $(DESTDIR)$(PREFIX)/lib INCLUDEDIR := $(DESTDIR)$(PREFIX)/include OBJECTS := canonpath.o errors.o hash.o key.o mdex.o mtree.o q.o router.o sync.o @OBJMLD@ ifeq ($(OSNAME),Linux) OBJECTS += if_linux.o else ifeq ($(OSNAME),FreeBSD) OBJECTS += if_bsd.o else ifeq ($(OSNAME),NetBSD) OBJECTS += if_bsd.o else ifeq ($(OSNAME),OpenBSD) OBJECTS += if_bsd.o else OBJECTS += if.o endif LDLIBS += @LIBBLAKE3@ @LIBSODIUM@ @LIBLCRQ@ @LIBS@ HEADERS = ../include/librecast/*.h @MLD_HEADERS@ CFLAGS += -I../libs/blake3/c CFLAGS += -I../libs/libmld/include LDFLAGS += -L../libs/blake3/c LDFLAGS += -L../libs/libmld/src LIBS += -llcrq ifeq ($(OSNAME),Darwin) SOFILE := lib$(LIBNAME).dylib SOOPT := -install_name else SOFILE := lib$(LIBNAME).so SOOPT := -soname endif SOFILES := $(SOFILE) ABIFILE := $(SOFILE).$(ABIVERS) MAJFILE := $(SOFILE).$(SOMAJOR) all: $(SOFILES) $(SOFILE): librecast.o $(OBJECTS) $(CC) $(CFLAGS) -shared $(LDFLAGS) -Wl,$(SOOPT),$(ABIFILE) -o $@ $^ $(LDLIBS) ln -sf $@ $(ABIFILE) # required for tests %.o: %.c %.h librecast_pvt.h $(HEADERS) install: $(SOFILES) $(INSTALL) -d $(LIBDIR) $(INSTALL) -d $(INCLUDEDIR) $(INSTALL) -d $(INCLUDEDIR)/librecast $(INSTALL_DATA) $(SOFILE) $(LIBDIR)/$(ABIFILE) $(INSTALL_DATA) ../include/*.h $(INCLUDEDIR) $(INSTALL_DATA) $(HEADERS) $(INCLUDEDIR)/librecast ln -sf $(ABIFILE) $(LIBDIR)/$(SOFILE) ln -sf $(ABIFILE) $(LIBDIR)/$(MAJFILE) .PHONY: clean realclean uninstall uninstall: $(RM) $(foreach f,$(SOFILES),$(DESTDIR)$(LIBDIR)/$f.$(VERSION)) $(RM) $(INCLUDEDIR)/librecast/*.h $(RM) $(INCLUDEDIR)/librecast.h cd $(LIBDIR) && $(RM) $(SOFILE) $(ABIFILE) $(MAJFILE) clean: $(RM) *.o $(SOFILE) $(ABIFILE) realclean: clean $(RM) Makefile config.h librecast/src/canonpath.c000066400000000000000000000062031502456746400157520ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2023-2024 Brett Sheffield */ /* canonpath() was adapted from glibc realpath(3): Copyright (C) 1996-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 char *canonpath(const char *name) { char *rpath, *dest; const char *start, *end, *rpath_limit; long int path_max; if (name == NULL) return (errno = EINVAL), NULL; if (name[0] == '\0') return (errno = ENOENT), NULL; #ifdef PATH_MAX path_max = PATH_MAX; #else path_max = pathconf(name, _PC_PATH_MAX); if (path_max <= 0) path_max = 1024; #endif rpath = malloc(path_max); if (rpath == NULL) return NULL; rpath_limit = rpath + path_max; if (name[0] != '/') { if (!getcwd(rpath, path_max)) { rpath[0] = '\0'; goto error; } #ifdef HAVE_RAWMEMCHR dest = rawmemchr(rpath, '\0'); #else dest = memchr(rpath, '\0', path_max); #endif } else { rpath[0] = '/'; dest = rpath + 1; } for (start = end = name; *start; start = end) { struct stat st; /* Skip sequence of multiple path-separators. */ while (*start == '/') ++start; /* Find end of path component. */ for (end = start; *end && *end != '/'; ++end); if (end - start == 0) break; else if (end - start == 1 && start[0] == '.'); else if (end - start == 2 && start[0] == '.' && start[1] == '.') { /* Back up to previous component, ignore if at root already. */ if (dest > rpath + 1) while ((--dest)[-1] != '/'); } else { size_t len, new_size; if (dest[-1] != '/') *dest++ = '/'; if (dest + (end - start) >= rpath_limit) { ptrdiff_t dest_offset = dest - rpath; char *new_rpath; new_size = rpath_limit - rpath; if (end - start + 1 > path_max) new_size += end - start + 1; else new_size += path_max; new_rpath = (char *) realloc(rpath, new_size); if (new_rpath == NULL) goto error; rpath = new_rpath; rpath_limit = rpath + new_size; dest = rpath + dest_offset; } len = end - start; dest = (char *)memcpy(dest, start, len) + len; *dest = '\0'; if (lstat(rpath, &st) < 0) goto error; if (!S_ISDIR(st.st_mode) && *end != '\0') { errno = ENOTDIR; goto error; } } } if (dest > rpath + 1 && dest[-1] == '/') --dest; *dest = '\0'; return rpath; error: free(rpath); return NULL; } librecast/src/canonpath.h000066400000000000000000000003741502456746400157620ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2023 Brett Sheffield */ /* canonpath() is the same as glibc's realpath(3), * except it does not resolve symlinks. */ char *canonpath(const char *name); librecast/src/config.h.in000066400000000000000000000210101502456746400156470ustar00rootroot00000000000000/* src/config.h.in. Generated from configure.ac by autoheader. */ /* Define to 1 if you have the `arc4random_uniform' function. */ #undef HAVE_ARC4RANDOM_UNIFORM /* Define to 1 if you have the header file. */ #undef HAVE_ARPA_INET_H /* Define to 1 to use the `blake3' library for hashing. */ #undef HAVE_BLAKE3 /* Define to 1 if your system has a working `chown' function. */ #undef HAVE_CHOWN /* Define to 1 if you have the `clock_gettime' function. */ #undef HAVE_CLOCK_GETTIME /* Define to 1 if you have the header file. */ #undef HAVE_ENDIAN_H /* Define to 1 if you have the `epoll_create1' function. */ #undef HAVE_EPOLL_CREATE1 /* Define to 1 if you have the header file. */ #undef HAVE_FCNTL_H /* Define to 1 if you have the `ftruncate' function. */ #undef HAVE_FTRUNCATE /* Define to 1 if you have the `getcwd' function. */ #undef HAVE_GETCWD /* Define to 1 if you have the `getpagesize' function. */ #undef HAVE_GETPAGESIZE /* Define to 1 if you have the header file. */ #undef HAVE_INTTYPES_H /* Define to 1 if you have the `kqueue' function. */ #undef HAVE_KQUEUE /* Define to 1 if you have the `dl' library (-ldl). */ #undef HAVE_LIBDL /* Define to 1 if you have the header file. */ #undef HAVE_LIBKERN_OSBYTEORDER_H /* Define to 1 if you have the `lcrq' library (-llcrq). */ #undef HAVE_LIBLCRQ /* Define to 1 if you have the `m' library (-lm). */ #undef HAVE_LIBM /* Define to 1 if you have the `pthread' library (-lpthread). */ #undef HAVE_LIBPTHREAD /* Define to 1 if you have the `sodium' library (-lsodium). */ #undef HAVE_LIBSODIUM /* Define to 1 if you have the header file. */ #undef HAVE_LINUX_NETLINK_H /* Define to 1 if you have the `memchr' function. */ #undef HAVE_MEMCHR /* Define to 1 if you have the `memset' function. */ #undef HAVE_MEMSET /* Define to 1 if you have the `mkdir' function. */ #undef HAVE_MKDIR /* Define to 1 to use the MLD library. */ #undef HAVE_MLD /* Define to 1 if you have a working `mmap' system call. */ #undef HAVE_MMAP /* Define to 1 if you have the `munmap' function. */ #undef HAVE_MUNMAP /* Define to 1 if you have the header file. */ #undef HAVE_NETDB_H /* Define to 1 if you have the header file. */ #undef HAVE_NETINET_IN_H /* Define to 1 if you have the header file. */ #undef HAVE_NET_IF_TAP_H /* Define to 1 if you have the header file. */ #undef HAVE_NET_IF_TUN_H /* Define to 1 if you have the `pathconf' function. */ #undef HAVE_PATHCONF /* Define to 1 if you have the `poll' function. */ #undef HAVE_POLL /* Define to 1 if the system has the type `ptrdiff_t'. */ #undef HAVE_PTRDIFF_T /* Define to 1 if you have the `rawmemchr' function. */ #undef HAVE_RAWMEMCHR /* Define to 1 if you have the `realpath' function. */ #undef HAVE_REALPATH /* Define to 1 if you have the `recvmmsg' function. */ #undef HAVE_RECVMMSG /* Define to 1 if you have the `rq_oti' function. */ #undef HAVE_RQ_OTI /* Define to 1 if you have the `socket' function. */ #undef HAVE_SOCKET /* Define to 1 if you have the header file. */ #undef HAVE_STDINT_H /* Define to 1 if you have the header file. */ #undef HAVE_STDIO_H /* Define to 1 if you have the header file. */ #undef HAVE_STDLIB_H /* Define to 1 if you have the `strdup' function. */ #undef HAVE_STRDUP /* Define to 1 if you have the `strerror' function. */ #undef HAVE_STRERROR /* Define to 1 if you have the header file. */ #undef HAVE_STRINGS_H /* Define to 1 if you have the header file. */ #undef HAVE_STRING_H /* Define to 1 if you have the `strndup' function. */ #undef HAVE_STRNDUP /* Define to 1 if you have the `strtoull' function. */ #undef HAVE_STRTOULL /* Define to 1 if you have the header file. */ #undef HAVE_SYS_ENDIAN_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_IOCTL_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_PARAM_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_SOCKET_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_STAT_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_TIME_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_TYPES_H /* Define to 1 if you have the header file. */ #undef HAVE_UNISTD_H /* Define to 1 if you have the `utimensat' function. */ #undef HAVE_UTIMENSAT /* Define to 1 if you have the `utimes' function. */ #undef HAVE_UTIMES /* Define to 1 if you have the header file. */ #undef HAVE_UTIME_H /* Define to 1 if the system has the type `_Bool'. */ #undef HAVE__BOOL /* Define to 1 if `lstat' dereferences a symlink specified with a trailing slash. */ #undef LSTAT_FOLLOWS_SLASHED_SYMLINK /* Define to the address where bug reports for this package should be sent. */ #undef PACKAGE_BUGREPORT /* Define to the full name of this package. */ #undef PACKAGE_NAME /* Define to the full name and version of this package. */ #undef PACKAGE_STRING /* Define to the one symbol short name of this package. */ #undef PACKAGE_TARNAME /* Define to the home page for this package. */ #undef PACKAGE_URL /* Define to the version of this package. */ #undef PACKAGE_VERSION /* Define to 1 if all of the C90 standard headers exist (not just the ones required in a freestanding environment). This macro is provided for backward compatibility; new code need not use it. */ #undef STDC_HEADERS /* Define for Solaris 2.5.1 so the uint32_t typedef from , , or is not used. If the typedef were allowed, the #define below would cause a syntax error. */ #undef _UINT32_T /* Define for Solaris 2.5.1 so the uint64_t typedef from , , or is not used. If the typedef were allowed, the #define below would cause a syntax error. */ #undef _UINT64_T /* Define for Solaris 2.5.1 so the uint8_t typedef from , , or is not used. If the typedef were allowed, the #define below would cause a syntax error. */ #undef _UINT8_T /* Define to `int' if doesn't define. */ #undef gid_t /* Define to `__inline__' or `__inline' if that's what the C compiler calls it, or to nothing if 'inline' is not supported under any name. */ #ifndef __cplusplus #undef inline #endif /* Define to the type of a signed integer type of width exactly 16 bits if such a type exists and the standard includes do not define it. */ #undef int16_t /* Define to the type of a signed integer type of width exactly 32 bits if such a type exists and the standard includes do not define it. */ #undef int32_t /* Define to the type of a signed integer type of width exactly 64 bits if such a type exists and the standard includes do not define it. */ #undef int64_t /* Define to `int' if does not define. */ #undef mode_t /* Define to `long int' if does not define. */ #undef off_t /* Define to the equivalent of the C99 'restrict' keyword, or to nothing if this is not supported. Do not define if restrict is supported only directly. */ #undef restrict /* Work around a bug in older versions of Sun C++, which did not #define __restrict__ or support _Restrict or __restrict__ even though the corresponding Sun C compiler ended up with "#define restrict _Restrict" or "#define restrict __restrict__" in the previous line. This workaround can be removed once we assume Oracle Developer Studio 12.5 (2016) or later. */ #if defined __SUNPRO_CC && !defined __RESTRICT && !defined __restrict__ # define _Restrict # define __restrict__ #endif /* Define to `unsigned int' if does not define. */ #undef size_t /* Define to `int' if does not define. */ #undef ssize_t /* Define to `int' if doesn't define. */ #undef uid_t /* Define to the type of an unsigned integer type of width exactly 16 bits if such a type exists and the standard includes do not define it. */ #undef uint16_t /* Define to the type of an unsigned integer type of width exactly 32 bits if such a type exists and the standard includes do not define it. */ #undef uint32_t /* Define to the type of an unsigned integer type of width exactly 64 bits if such a type exists and the standard includes do not define it. */ #undef uint64_t /* Define to the type of an unsigned integer type of width exactly 8 bits if such a type exists and the standard includes do not define it. */ #undef uint8_t librecast/src/cov.c000066400000000000000000000000471502456746400145660ustar00rootroot00000000000000/* empty modeling file for coverity */ librecast/src/errors.c000066400000000000000000000004061502456746400153120ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2017-2021 Brett Sheffield */ #include char *lc_error_msg(int e) { switch (e) { LC_ERROR_CODES(LC_ERROR_MSG) } return "Unknown error"; } librecast/src/hash.c000066400000000000000000000053711502456746400147270ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2020-2021 Brett Sheffield */ #include "hash.h" #include #include #ifndef sodium_bin2hex /* Derived from original code by CodesInChaos * sodium_bin2hex() from libsodium * License: ISC */ char * sodium_bin2hex(char *const hex, const size_t hex_maxlen, const unsigned char *const bin, const size_t bin_len) { size_t i = (size_t) 0U; unsigned int x; int b; int c; assert(bin_len < SIZE_MAX / 2 && hex_maxlen > bin_len * 2U); // sodium_misuse() (void)hex_maxlen; while (i < bin_len) { c = bin[i] & 0xf; b = bin[i] >> 4; x = (unsigned char) (87U + c + (((c - 10U) >> 8) & ~38U)) << 8 | (unsigned char) (87U + b + (((b - 10U) >> 8) & ~38U)); hex[i * 2U] = (char) x; x >>= 8; hex[i * 2U + 1U] = (char) x; i++; } hex[i * 2U] = 0U; return hex; } #endif #ifdef HASH_TYPE void hash_hex_debug(FILE *fd, unsigned char *hash, size_t len) { char hex[HEXLEN]; sodium_bin2hex(hex, HEXLEN, hash, len); fprintf(fd, "%s\n", hex); } int hash_generic_key(unsigned char *hash, size_t hashlen, unsigned char *in, size_t inlen, unsigned char *key, size_t keylen) { #if (HASH_TYPE == HASH_BLAKE3) blake3_hasher hasher; blake3_hasher_init(&hasher); blake3_hasher_update(&hasher, in, inlen); blake3_hasher_update(&hasher, key, keylen); blake3_hasher_finalize(&hasher, hash, hashlen); return 0; #elif (HASH_TYPE == HASH_BLAKE2) return crypto_generichash(hash, hashlen, in, inlen, key, keylen); #endif } int hash_generic(unsigned char *hash, size_t hashlen, unsigned char *in, size_t inlen) { #if (HASH_TYPE == HASH_BLAKE3) blake3_hasher hasher; blake3_hasher_init(&hasher); blake3_hasher_update(&hasher, in, inlen); blake3_hasher_finalize(&hasher, hash, hashlen); return 0; #elif (HASH_TYPE == HASH_BLAKE2) return hash_generic_key(hash, hashlen, in, inlen, NULL, 0); #endif } void hash_final(hash_state *state, unsigned char *hash, size_t hashlen) { #if (HASH_TYPE == HASH_BLAKE3) blake3_hasher_finalize(state, hash, hashlen); #elif (HASH_TYPE == HASH_BLAKE2) crypto_generichash_final(state, hash, hashlen); #endif } void hash_update(hash_state *state, unsigned char *msg, size_t msglen) { #if (HASH_TYPE == HASH_BLAKE3) blake3_hasher_update(state, msg, msglen); #elif (HASH_TYPE == HASH_BLAKE2) crypto_generichash_update(state, msg, msglen); #endif } void hash_init(hash_state *state, unsigned char *key, size_t keylen, size_t hashlen) { #if (HASH_TYPE == HASH_BLAKE3) (void) hashlen; if (key) { assert(keylen == 32); blake3_hasher_init_keyed(state, key); } else { blake3_hasher_init(state); } #elif (HASH_TYPE == HASH_BLAKE2) crypto_generichash_init(state, key, keylen, hashlen); #endif } #endif /* ifdef HASH_TYPE */ librecast/src/hash.h000066400000000000000000000003271502456746400147300ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2020-2021 Brett Sheffield */ #ifndef _HASH_H #define _HASH_H 1 #include #endif /* _HASH_H */ librecast/src/if.c000066400000000000000000000027361502456746400144040ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2017-2021 Brett Sheffield */ #include #include "librecast_pvt.h" #include #include #include #include #include #include #include #include #include #include #include static inline int lc_ctrl_socket(void) { return socket(AF_LOCAL, SOCK_STREAM, 0); } int lc_bridge_del(lc_ctx_t *ctx, const char *brname) { (void)ctx; (void)brname; return ENOTSUP; } int lc_bridge_add(lc_ctx_t *ctx, const char *brname) { (void)ctx; (void)brname; return ENOTSUP; } int lc_bridge_delif(lc_ctx_t *ctx, const char *brname, const char *ifname) { (void)ctx; (void)brname; (void)ifname; return ENOTSUP; } int lc_bridge_addif(lc_ctx_t *ctx, const char *brname, const char *ifname) { (void)ctx; (void)brname; (void)ifname; return ENOTSUP; } int lc_link_set(lc_ctx_t *ctx, char *ifname, int up) { struct ifreq ifr; int err = 0; if (ctx->sock == -1) ctx->sock = lc_ctrl_socket(); if (ctx->sock == -1) return -1; memset(&ifr, 0, sizeof(ifr)); strncpy(ifr.ifr_name, ifname, IFNAMSIZ - 1); if (ioctl(ctx->sock, SIOCGIFFLAGS, &ifr) == -1) { return -1; } ifr.ifr_flags = (up) ? ifr.ifr_flags | IFF_UP : ifr.ifr_flags & ~IFF_UP; err = ioctl(ctx->sock, SIOCSIFFLAGS, &ifr); return err; } int lc_tap_create(char *ifname) { (void)ifname; return ENOTSUP; } librecast/src/if_bsd.c000066400000000000000000000055701502456746400152330ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2017-2021 Brett Sheffield */ #include #include "librecast_pvt.h" #include #include #include #include #if HAVE_NET_IF_TAP_H # include #elif HAVE_NET_IF_TUN_H # include #endif #include #include #include #include #include #include #include static inline int lc_ctrl_socket(void) { return socket(AF_LOCAL, SOCK_STREAM, 0); } int lc_bridge_del(lc_ctx_t *ctx, const char *brname) { (void)ctx; (void)brname; errno = ENOTSUP; return -1; } int lc_bridge_add(lc_ctx_t *ctx, const char *brname) { (void)ctx; (void)brname; errno = ENOTSUP; return -1; } int lc_bridge_delif(lc_ctx_t *ctx, const char *brname, const char *ifname) { (void)ctx; (void)brname; (void)ifname; errno = ENOTSUP; return -1; } int lc_bridge_addif(lc_ctx_t *ctx, const char *brname, const char *ifname) { (void)ctx; (void)brname; (void)ifname; errno = ENOTSUP; return -1; } int lc_link_set(lc_ctx_t *ctx, char *ifname, int up) { struct ifreq ifr; int err = 0; if (ctx->sock == -1) ctx->sock = lc_ctrl_socket(); if (ctx->sock == -1) return -1; memset(&ifr, 0, sizeof(ifr)); strncpy(ifr.ifr_name, ifname, IFNAMSIZ - 1); if (ioctl(ctx->sock, SIOCGIFFLAGS, &ifr) == -1) { return -1; } ifr.ifr_flags = (up) ? ifr.ifr_flags | IFF_UP : ifr.ifr_flags & ~IFF_UP; err = ioctl(ctx->sock, SIOCSIFFLAGS, &ifr); return err; } int lc_tuntap_create(char *ifname, int flags) { int fd = -1; #if defined(TAPGIFNAME) /* On {Free,Net}BSD we open the special cloning device /dev/tap and * then check which interface name we were assigned */ struct ifreq ifr; if ((fd = open("/dev/tap", O_RDWR)) == -1) { return -1; } memset(&ifr, 0, sizeof(ifr)); ifr.ifr_flags = flags; if (ifname[0]) strncpy(ifr.ifr_name, ifname, IFNAMSIZ - 1); if (ioctl(fd, TAPGIFNAME, (void *) &ifr) == -1) { close(fd); return -1; } strcpy(ifname, ifr.ifr_name); #elif defined(TUNGIFINFO) /* On OpenBSD there is no cloning device, so we iterate through * possible interfaces until we succeed in opening one */ char devname[8]; char tapname[16]; for (int i = 0; i < 255; i++) { snprintf(devname, sizeof devname, "tap%i", i); snprintf(tapname, sizeof tapname, "/dev/%s", devname); errno = 0; if ((fd = open(tapname, O_RDWR)) == -1) { if (errno == ENXIO) break; /* Not that many devices configured */ continue; } break; } if (flags) { struct tuninfo tinfo = { .flags = flags }; if (ioctl(fd, TUNSIFINFO, (void *)&tinfo) == -1) { close(fd); fd = -1; } } if (fd > 0) strcpy(ifname, devname); #else (void)ifname; (void)flags; errno = ENOTSUP; fd = -1; #endif return fd; } int lc_tap_create(char *ifname) { return lc_tuntap_create(ifname, 0); } librecast/src/if_linux.c000066400000000000000000000075011502456746400156160ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2017-2022 Brett Sheffield */ /* Contains code derived from libbridge (part of bridge-utils) * Copyright (C) 2000-2017 Lennert Buytenhek, Stephen Hemminger et al */ #include #include "librecast_pvt.h" #include #include #include #include #ifdef __linux__ #define _LINUX_IF_H /* https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=822393 */ #include #include #include #include #endif #include #include #include #include #include #include #include static inline int lc_ctrl_socket(void) { return socket(AF_LOCAL, SOCK_STREAM, 0); } int lc_bridge_del(lc_ctx_t *ctx, const char *brname) { int ret; if (ctx->sock == -1) ctx->sock = lc_ctrl_socket(); if (ctx->sock == -1) return -1; #ifdef SIOCBRDELBR ret = ioctl(ctx->sock, SIOCBRDELBR, brname); if (ret < 0) #endif { char _br[IFNAMSIZ]; unsigned long arg[3] = { BRCTL_DEL_BRIDGE, (unsigned long) _br }; strncpy(_br, brname, IFNAMSIZ - 1); ret = ioctl(ctx->sock, SIOCSIFBR, arg); } return ret < 0 ? errno : 0; } int lc_bridge_add(lc_ctx_t *ctx, const char *brname) { int ret; if (ctx->sock == -1) ctx->sock = lc_ctrl_socket(); if (ctx->sock == -1) return -1; #ifdef SIOCBRADDBR ret = ioctl(ctx->sock, SIOCBRADDBR, brname); if (ret < 0) #endif { char _br[IFNAMSIZ]; unsigned long arg[3] = { BRCTL_ADD_BRIDGE, (unsigned long) _br }; strncpy(_br, brname, IFNAMSIZ - 1); ret = ioctl(ctx->sock, SIOCSIFBR, arg); } return ret < 0 ? errno : 0; } int lc_bridge_delif(lc_ctx_t *ctx, const char *brname, const char *ifname) { struct ifreq ifr; int err; int ifx = if_nametoindex(ifname); if (ifx == 0) return ENODEV; if (ctx->sock == -1) ctx->sock = lc_ctrl_socket(); if (ctx->sock == -1) return -1; memset(&ifr, 0, sizeof(ifr)); strncpy(ifr.ifr_name, brname, IFNAMSIZ - 1); #ifdef SIOCBRDELIF ifr.ifr_ifindex = ifx; err = ioctl(ctx->sock, SIOCBRDELIF, &ifr); if (err < 0) #endif { unsigned long args[4] = { BRCTL_DEL_IF, ifx, 0, 0 }; ifr.ifr_data = (char *) args; err = ioctl(ctx->sock, SIOCDEVPRIVATE, &ifr); } return err < 0 ? errno : 0; } int lc_bridge_addif(lc_ctx_t *ctx, const char *brname, const char *ifname) { struct ifreq ifr; int err; int ifx = if_nametoindex(ifname); if (ifx == 0) return ENODEV; if (ctx->sock == -1) ctx->sock = lc_ctrl_socket(); if (ctx->sock == -1) return -1; memset(&ifr, 0, sizeof(ifr)); strncpy(ifr.ifr_name, brname, IFNAMSIZ - 1); #ifdef SIOCBRADDIF ifr.ifr_ifindex = ifx; err = ioctl(ctx->sock, SIOCBRADDIF, &ifr); if (err < 0) #endif { unsigned long args[4] = { BRCTL_ADD_IF, ifx, 0, 0 }; ifr.ifr_data = (char *) args; err = ioctl(ctx->sock, SIOCDEVPRIVATE, &ifr); } return err < 0 ? errno : 0; } int lc_link_set(lc_ctx_t *ctx, char *ifname, int up) { struct ifreq ifr; int err = 0; if (ctx->sock == -1) ctx->sock = lc_ctrl_socket(); if (ctx->sock == -1) return -1; memset(&ifr, 0, sizeof(ifr)); strncpy(ifr.ifr_name, ifname, IFNAMSIZ - 1); if (ioctl(ctx->sock, SIOCGIFFLAGS, &ifr) == -1) { return -1; } ifr.ifr_flags = (up) ? ifr.ifr_flags | IFF_UP : ifr.ifr_flags & ~IFF_UP; err = ioctl(ctx->sock, SIOCSIFFLAGS, &ifr); return err; } int lc_tuntap_create(char *ifname, int flags) { struct ifreq ifr; int fd; if ((fd = open("/dev/net/tun", O_RDWR)) == -1) { return -1; } memset(&ifr, 0, sizeof(ifr)); ifr.ifr_flags = flags; if (ifname[0]) strncpy(ifr.ifr_name, ifname, IFNAMSIZ - 1); if (ioctl(fd, TUNSETIFF, (void *) &ifr) == -1) { close(fd); return -1; } strcpy(ifname, ifr.ifr_name); return fd; } int lc_tap_create(char *ifname) { return lc_tuntap_create(ifname, IFF_TAP | IFF_NO_PI); } librecast/src/key.c000066400000000000000000000052321502456746400145700ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2025 Brett Sheffield */ #define _GNU_SOURCE /* recvmmsg */ #include #include #include #include int lc_token_new(lc_token_t *token, lc_keypair_t *signing_key, uint8_t *bearer_key, lc_channel_t *chan, uint8_t capbits, uint64_t valid_sec) { const unsigned char *m = (unsigned char *)token; const unsigned long long mlen = sizeof(lc_token_t) - crypto_sign_BYTES; struct timespec expires; token->version = 0xff; token->capbits = capbits; token->expires = valid_sec; if (valid_sec) { if (clock_gettime(CLOCK_REALTIME, &expires) == -1) return -1; token->expires += expires.tv_sec; } memcpy(token->channel, lc_channel_get_hash(chan), sizeof token->channel); memcpy(token->signkey, signing_key->pk, sizeof token->signkey); memcpy(token->bearkey, bearer_key, sizeof token->bearkey); if (crypto_sign_detached(token->sig, NULL, m, mlen, signing_key->sk) == -1) return (errno = ENOTRECOVERABLE), -1; return 0; } int lc_keypair_new(lc_keypair_t *key, int flags) { if (flags & LC_KEY_SIG) { return crypto_sign_keypair(key->pk, key->sk); } if (flags & LC_KEY_ENC) { return crypto_box_keypair(key->pk, key->sk); } return (errno = EINVAL), -1; } int lc_keyring_init(lc_keyring_t *keyring, size_t nkeys) { keyring->key = calloc(nkeys, sizeof(uint8_t *)); if (!keyring->key) return -1; keyring->nkeys = 0; keyring->len = nkeys; return 0; } void lc_keyring_free(lc_keyring_t *keyring) { free(keyring->key); } int lc_keyring_has(lc_keyring_t *keyring, uint8_t *key) { if (keyring->key) { for (size_t n = 0; n < keyring->nkeys; n++) { if (!keyring->key[n]) continue; if (!memcmp(keyring->key[n], key, crypto_sign_PUBLICKEYBYTES)) return -1; } } return 0; } int lc_keyring_add(lc_keyring_t *keyring, uint8_t *key) { if (keyring->nkeys >= keyring->len) return (errno = ENOMEM), -1; keyring->key[keyring->nkeys++] = key; return 0; } int lc_keyring_del(lc_keyring_t *keyring, uint8_t *key) { if (keyring->key) { for (size_t n = 0; n < keyring->nkeys; n++) { if (!keyring->key[n]) continue; if (!memcmp(keyring->key[n], key, crypto_sign_PUBLICKEYBYTES)) { /* key found, delete it */ keyring->nkeys--; if (keyring->nkeys > 0) { size_t sz = sizeof(uint8_t *) * (keyring->nkeys - n); memmove(&keyring->key[n], &keyring->key[n+1], sz); } return 0; } } } return (errno = ENOKEY), -1; } void lc_channel_filter_set(lc_channel_t *chan, lc_filter_t *filter) { chan->filter = filter; } void lc_channel_token_set(lc_channel_t *chan, lc_token_t *token) { chan->token = token; } librecast/src/librecast.c000066400000000000000000002210071502456746400157500ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2017-2025 Brett Sheffield */ #define _GNU_SOURCE #include #include #include #ifdef HAVE_LIBLCRQ #include #endif #ifdef HAVE_MLD #include #endif #include "hash.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_LINUX_NETLINK_H #include #include #include #endif #ifdef HAVE_LIBLCRQ # define ESI(row, col) chan->ESI[row * nesi + col] # define ESIr(row) &chan->ESI[row * nesi] # define BLK(row, col) &chan->rq_blk[(row * nesi + col) * T] #endif #if defined(HAVE_LIBLCRQ) && (HAVE_RQ_OTI) # define OTI_OH sizeof(rq_oti_t) + sizeof(rq_scheme_t) #else # define OTI_OH 0 #endif /* define macro for lcrq < 0.1.0 */ #ifndef rq_pidset # define rq_pidset(sbn, esi) ((sbn << 24) | (esi & 0x00ffffff)); #endif #ifndef IPV6_MIN_MTU #define IPV6_MIN_MTU 1280 #endif #define SEND_RETRIES 254 #define SEND_RETRY_DELAY 100 lc_ctx_t *ctx_list = NULL; static void lc_op_data_handler(lc_socket_call_t *sc, lc_message_t *msg); static void lc_op_ping_handler(lc_socket_call_t *sc, lc_message_t *msg); static void lc_op_pong_handler(lc_socket_call_t *sc, lc_message_t *msg); int (*lc_msg_logger)(lc_channel_t *, lc_message_t *, void *logdb) = NULL; void (*lc_op_handler[LC_OP_MAX])(lc_socket_call_t *, lc_message_t *) = { lc_op_data_handler, lc_op_ping_handler, lc_op_pong_handler, }; int lc_getrandom(void *buf, size_t buflen) { int err, fd; if ((fd = open("/dev/urandom", O_RDONLY)) == -1) return -1; err = read(fd, buf, buflen); close(fd); return err; } lc_ctx_t *lc_socket_ctx(lc_socket_t *sock) { return sock->ctx; } lc_ctx_t *lc_channel_ctx(lc_channel_t *chan) { return chan->ctx; } rq_t *lc_channel_rq(lc_channel_t *chan) { #ifdef HAVE_LIBLCRQ return chan->rq; #else (void)chan; return (errno = ENOTSUP), NULL; #endif } int lc_ctx_rq_overhead(lc_ctx_t *ctx, int overhead) { #ifdef HAVE_LIBLCRQ return (ctx->rq_oh = overhead); #else (void)ctx, (void)overhead; return (errno = ENOTSUP), -1; #endif } int lc_channel_rq_overhead(lc_channel_t *chan, int overhead) { #ifdef HAVE_LIBLCRQ return (chan->rq_oh = overhead); #else (void)chan, (void)overhead; return (errno = ENOTSUP), -1; #endif } lc_socket_t *lc_channel_socket(lc_channel_t *chan) { return chan->sock; } unsigned char *lc_channel_get_hash(lc_channel_t *chan) { return chan->hash; } struct in6_addr *lc_channel_in6addr(lc_channel_t *chan) { if (!chan) return (errno = EINVAL), NULL; if (!chan->sa.sin6_family) { chan->sa.sin6_family = AF_INET6; lc_hashtoaddr(&chan->sa.sin6_addr, chan->hash, HASHSIZE, LC_DEFAULT_FLAGS); } if (!chan->sa.sin6_port) chan->sa.sin6_port = htons(LC_DEFAULT_PORT); return &(chan->sa.sin6_addr); } struct sockaddr_in6 *lc_channel_sockaddr(lc_channel_t *chan) { return &chan->sa; } int lc_channel_socket_raw(lc_channel_t *chan) { return chan->sock->sock; } lc_socket_t * lc_socket_by_fd(lc_ctx_t *ctx, int fd) { lc_socket_t *sock = NULL; pthread_mutex_lock(&ctx->mtx); for (lc_socket_t *s = ctx->sock_list; s; s = s->next) { if (s->sock == fd) { sock = s; break; } } pthread_mutex_unlock(&ctx->mtx); return sock; } void lc_ctx_ifx(lc_ctx_t *ctx, unsigned int ifx) { ctx->ifx = ifx; } void lc_ctx_ratelimit(lc_ctx_t *ctx, size_t bps_out, size_t bps_in) { ctx->bps_out = bps_out; ctx->bps_in = bps_in; } void lc_channel_ratelimit(lc_channel_t *chan, size_t bps_out, size_t bps_in) { chan->bps_out = bps_out; chan->bps_in = bps_in; } int lc_socket_raw(lc_socket_t *sock) { return sock->sock; } void *lc_msg_data(lc_message_t *msg) { return (msg) ? msg->data: NULL; } int lc_msg_get(lc_message_t *msg, lc_msg_attr_t attr, void **value) { if (!msg || !value) return LC_ERROR_INVALID_PARAMS; switch (attr) { case LC_ATTR_DATA: *value = msg->data; break; case LC_ATTR_LEN: *value = (void *)&msg->len; break; case LC_ATTR_OPCODE: *value = (void *)&msg->op; break; default: return LC_ERROR_MSG_ATTR_UNKNOWN; } return 0; } int lc_msg_set(lc_message_t *msg, lc_msg_attr_t attr, void *value) { if (!msg) return LC_ERROR_INVALID_PARAMS; switch (attr) { case LC_ATTR_DATA: msg->data = value; break; case LC_ATTR_LEN: msg->len = *(lc_len_t *)value; break; case LC_ATTR_OPCODE: msg->op = *(lc_opcode_t *)value; break; default: return LC_ERROR_MSG_ATTR_UNKNOWN; } return 0; } int lc_msg_id(lc_message_t *msg, unsigned char *id, size_t len) { #ifndef HASH_TYPE return (errno = ENOTSUP), -1; #else hash_state state; hash_init(&state, NULL, 0, len); hash_update(&state, (unsigned char *)msg->data, msg->len); hash_update(&state, (unsigned char *)msg->srcaddr, sizeof(struct in6_addr)); hash_final(&state, id, len); return 0; #endif } int lc_socket_getopt(lc_socket_t *sock, int optname, void *optval, socklen_t *optlen) { if (sock->type != LC_SOCK_IN6) return (errno = ENOTSUP), -1; return getsockopt(sock->sock, IPPROTO_IPV6, optname, optval, optlen); } int lc_socket_setopt(lc_socket_t *sock, int optname, const void *optval, socklen_t optlen) { if (sock->type != LC_SOCK_IN6) return (errno = ENOTSUP), -1; return setsockopt(sock->sock, IPPROTO_IPV6, optname, optval, optlen); } int lc_socket_loop(lc_socket_t *sock, int val) { if (sock->type != LC_SOCK_IN6) return (errno = ENOTSUP), -1; return setsockopt(sock->sock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &val, sizeof val); } int lc_socket_ttl(lc_socket_t *sock, int val) { sock->ttl = val; if (sock->type != LC_SOCK_IN6) return 0; return setsockopt(sock->sock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &val, sizeof val); } lc_router_t *lc_socket_router(lc_socket_t *sock) { return sock->router; } static void *_free(void *msg, void *hint) { free(msg); return hint; } void lc_msg_free(void *arg) { lc_message_t *msg = (lc_message_t *)arg; if (msg->free) { msg->free(msg->data, msg->hint); msg->data = NULL; } } void *lc_msg_init(lc_message_t *msg) { return memset(msg, 0, sizeof(lc_message_t)); } int lc_msg_init_data(lc_message_t *msg, void *data, size_t len, lc_free_fn_t *f, void *hint) { lc_msg_init(msg); msg->len = len; msg->data = data; msg->free = f; msg->hint = hint; return 0; } int lc_msg_init_size(lc_message_t *msg, size_t len) { lc_msg_init(msg); msg->data = malloc(len); if (!msg->data) return -1; msg->len = len; msg->free = &_free; return 0; } int lc_ctx_coding_get(lc_ctx_t *ctx) { return ctx->coding; } int lc_ctx_coding_set(lc_ctx_t *ctx, int coding) { return (ctx->coding = coding); } int lc_socket_coding_get(lc_socket_t *sock) { return sock->ccoding; } int lc_socket_coding_set(lc_socket_t *sock, int coding) { return (sock->ccoding = coding); } int lc_channel_coding_get(lc_channel_t *chan) { return chan->coding; } int lc_channel_coding_set(lc_channel_t *chan, int coding) { if (chan->sock) chan->sock->ccoding |= coding; return (chan->coding = coding); } static int lc_ctx_keygetorset(lc_ctx_t *ctx, lc_key_t *key, int type, int set) { lc_key_t *k; switch (type) { case LC_CODE_SYMM: k = &ctx->key; break; case LC_CODE_PUBK: k = &ctx->pek; break; default: return (errno = EINVAL), -1; } if (set) { k->key = key->key; k->keylen = key->keylen; } else { key->key = k->key; key->keylen = k->keylen; } return 0; } static int lc_channel_keygetorset(lc_channel_t *chan, lc_key_t *key, int type, int set) { lc_key_t *k; switch (type) { case LC_CODE_SYMM: k = &chan->key; break; case LC_CODE_PUBK: k = &chan->pek; break; case LC_CODE_SIGN: k = &chan->ssk; break; default: return (errno = EINVAL), -1; } if (set) { k->key = key->key; k->keylen = key->keylen; } else { key->key = k->key; key->keylen = k->keylen; } return 0; } int lc_ctx_getkey(lc_ctx_t *ctx, lc_key_t *key, int type) { return lc_ctx_keygetorset(ctx, key, type, 0); } int lc_ctx_setkey(lc_ctx_t *ctx, lc_key_t *key, int type) { return lc_ctx_keygetorset(ctx, key, type, 1); } int lc_ctx_set_sym_key(lc_ctx_t *ctx, unsigned char *key, size_t len) { lc_key_t k = { .key = key, .keylen = len }; return lc_ctx_setkey(ctx, &k, LC_CODE_SYMM); } int lc_ctx_set_pub_key(lc_ctx_t *ctx, unsigned char *key, size_t len) { lc_key_t k = { .key = key, .keylen = len }; return lc_ctx_setkey(ctx, &k, LC_CODE_PUBK); } int lc_channel_getkey(lc_channel_t *chan, lc_key_t *key, int type) { return lc_channel_keygetorset(chan, key, type, 0); } int lc_channel_setkey(lc_channel_t *chan, lc_key_t *key, int type) { return lc_channel_keygetorset(chan, key, type, 1); } int lc_channel_set_sym_key(lc_channel_t *chan, unsigned char *key, size_t len) { lc_key_t k = { .key = key, .keylen = len }; return lc_channel_setkey(chan, &k, LC_CODE_SYMM); } int lc_channel_set_pub_key(lc_channel_t *chan, unsigned char *key, size_t len) { lc_key_t k = { .key = key, .keylen = len }; return lc_channel_setkey(chan, &k, LC_CODE_PUBK); } static void lc_close_nack_logger(lc_channel_logging_t *logging) { pthread_cancel(logging->nack_thread); pthread_join(logging->nack_thread, NULL); pthread_mutex_destroy(&logging->mutex); while (logging->oldest) { lc_packet_log_t * go = logging->oldest; logging->oldest = go->next; free(go); } free(logging); } static void free_gap_detect(lc_channel_gap_detect_t * gap_detect) { int saveerrno = errno; lc_socket_close(gap_detect->sock_nack); lc_channel_free(gap_detect->chan_nack); free(gap_detect); errno = saveerrno; } int lc_channel_detect_gaps(lc_channel_t *chan) { lc_channel_gap_detect_t * gap_detect = calloc(1, sizeof(lc_channel_gap_detect_t)); socklen_t looplen; int isloop; if (! gap_detect) return -1; gap_detect->next = 0; gap_detect->chan_nack = lc_channel_sidehash(chan, (void *)SIDE_CHANNEL_NACK, strlen(SIDE_CHANNEL_NACK)); if (! gap_detect->chan_nack) goto error; gap_detect->sock_nack = lc_socket_new(chan->ctx); if (! gap_detect->sock_nack) goto error; /* if the original channel had loopback we'll need that too */ looplen = sizeof(isloop); if (getsockopt(chan->sock->sock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &isloop, &looplen) == 0) if (isloop) if (lc_socket_loop(gap_detect->sock_nack, 1)) goto error; lc_channel_bind(gap_detect->sock_nack, gap_detect->chan_nack); if (chan->gap_detect) free_gap_detect(chan->gap_detect); chan->gap_detect = gap_detect; return 0; error: free_gap_detect(gap_detect); return -1; } static int do_gap_detection(lc_channel_gap_detect_t *gapd, lc_seq_t seq) { /* if we've never received a packet since setting this up, we'll assume packets * before this one have all arrived (no way to know) */ int duplicate = 0; if (! gapd->next) { gapd->next = seq + 1; gapd->bitmap = ~(uint64_t)0; return 0; } /* see if this is a retrasmission / arrived out of order */ if (seq < gapd->next) { /* arrived out of order, update the bitmap if this is one of the previous * 64 packets; * don't do "if (seq >= gapd->next - 64)" in case the subtraction overflows */ if (seq + 64 >= gapd->next) { if (gapd->bitmap & (uint64_t)1 << (seq + 64 - gapd->next)) duplicate = 1; gapd->bitmap |= (uint64_t)1 << (seq + 64 - gapd->next); } } else { /* we'll likely need to shift the bitmap so that it covers seq - 63 to seq; * if any bit we shift out is 0 that is the last chance to send a NACK for it */ while (gapd->next <= seq) { if (! (gapd->bitmap & ((uint64_t)1 << 63))) { uint64_t miss = htobe64(gapd->next - 64); lc_socket_send(gapd->sock_nack, &miss, sizeof(miss), 0); } gapd->bitmap <<= 1; gapd->next++; } /* now gapd->bitmap == seq + 1 so bit 0 needs to be set: we've seen seq! */ gapd->bitmap |= (uint64_t)1; } /* either way, check if there are any other NACKs we could do with sending; to avoid * sending too many NACKs for the same packet we only check packets older than seq */ if (~gapd->bitmap) { int bit; uint64_t mask = (uint64_t)1; lc_seq_t mseq = gapd->next - 1; for (bit = 0; bit < 64; bit++, mask <<= 1, mseq--) { if (mseq < seq && ! (gapd->bitmap & mask)) { uint64_t miss = htobe64(mseq); if (lc_socket_send(gapd->sock_nack, &miss, sizeof(miss), 0) == -1) duplicate = -1; } } } return duplicate; } int lc_channel_check_seqno(lc_channel_t *chan, lc_seq_t seq) { if (chan && chan->gap_detect) return do_gap_detection(chan->gap_detect, seq); else return 0; } /* remove channel from ctx list */ static void channel_unlink(lc_channel_t *chan) { pthread_mutex_lock(&chan->ctx->mtx); lc_channel_t *prev = NULL; lc_channel_t *next = aload(&chan->next); for (lc_channel_t *p = aload(&chan->ctx->chan_list); p; p = aload(&p->next)) { if (p == chan) { lc_channel_t **ptr = (prev) ? &prev->next : &chan->ctx->chan_list; CAE_loop(ptr, &p, next); break; } prev = p; } pthread_mutex_unlock(&chan->ctx->mtx); } void lc_channel_free(lc_channel_t * chan) { int err = errno; if (!chan) return; #ifdef HAVE_LIBLCRQ if (chan->rq) rq_free(chan->rq); if (chan->rq_blk) free (chan->rq_blk); if (chan->ESI) free(chan->ESI); #endif if (chan->logging) lc_close_nack_logger(chan->logging); if (chan->gap_detect) free_gap_detect(chan->gap_detect); channel_unlink(chan); int deleted = 0; if (CAE(&chan->deleted, &deleted, DELETE_LATER)) lc_channel_release(chan); errno = err; } static void chan_ratelimit(lc_channel_t *chan) { uint64_t nss, nse; double s, bps; struct timespec now = {0}; nss = chan->byt_reset.tv_nsec + chan->byt_reset.tv_sec * NANO; while (1) { if (clock_gettime(CLOCK_TAI, &now) == -1) break; nse = now.tv_nsec + now.tv_sec * NANO; s = (double)(nse - nss) / NANO; bps = chan->byt_out * 8 / s; if (bps < chan->bps_out) break; usleep(100); } } static void chan_byt_out(lc_channel_t *chan, size_t byt) { fetch_add(&chan->byt_out, byt); fetch_add(&chan->sock->byt_out, byt); } static ssize_t chan_sendmsg(lc_channel_t *chan, struct msghdr *msg, int flags, ssize_t ohead) { ssize_t rc = 0; if (flags & MSG_DROP) { for (int i = 0; i < (int)msg->msg_iovlen; i++) rc += msg->msg_iov[i].iov_len; } else { int retries = 0; send_again: rc = sendmsg(chan->sock->sock, msg, flags); if (rc == -1 && errno == ENOBUFS && retries++ < SEND_RETRIES) { usleep(SEND_RETRY_DELAY); goto send_again; } } if (rc > 0) chan_byt_out(chan, rc); if (rc > ohead) rc -= ohead; /* return information bytes */ return rc; } static void cleanup_freeifaddrs(void *arg) { if (arg) freeifaddrs(arg); } /* socket is not bound to an interface. Send on ALL multicast capable interfaces */ static ssize_t chan_sendmsg_unbound(lc_channel_t *chan, struct msghdr *msg, int flags) { int sock = chan->sock->sock; struct ifaddrs *ifap = NULL; ssize_t rc = 0; int oldstate; /* set cancelstate until we have cleanup macro ready */ pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldstate); rc = getifaddrs(&ifap); if (rc == -1) return -1; pthread_cleanup_push(cleanup_freeifaddrs, ifap); pthread_setcancelstate(oldstate, NULL); /* and relax */ for (struct ifaddrs *ifa = ifap; ifa; ifa = ifa->ifa_next) { if (ifa->ifa_addr == NULL) continue; if (ifa->ifa_addr->sa_family != AF_INET6) continue; /* IPv6 */ if (!(ifa->ifa_flags & IFF_MULTICAST)) continue; /* multicast */ unsigned int ifx = if_nametoindex(ifa->ifa_name); rc = setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_IF, &ifx, sizeof ifx); if (rc == -1) break; rc = chan_sendmsg(chan, msg, flags, 0); if (rc == -1) break; /* process each interface only once */ while (ifa->ifa_next && ifa->ifa_name == ifa->ifa_next->ifa_name) ifa = ifa->ifa_next; } pthread_cleanup_pop(1); /* freeifaddrs(ifap); */ return rc; } static ssize_t chan_sendmsg_tlv(lc_channel_t *chan, struct msghdr *msg, int flags, ssize_t overhead) { lc_tlv_t tlv_hash = { .type = LC_TLV_HASH, .len = HASHSIZE }; const int hdrs = 2; struct iovec iov[msg->msg_iovlen + hdrs]; const size_t iovlen = sizeof iov / sizeof iov[0]; iov[0].iov_base = &tlv_hash; iov[0].iov_len = sizeof tlv_hash; iov[1].iov_base = chan->hash; iov[1].iov_len = HASHSIZE; for (int i = 0; i < hdrs; i++) overhead += iov[i].iov_len; for (int i = 0; i < (int)msg->msg_iovlen; i++) { iov[i + hdrs].iov_base = msg->msg_iov[i].iov_base; iov[i + hdrs].iov_len = msg->msg_iov[i].iov_len; } msg->msg_iov = iov; msg->msg_iovlen = iovlen; return chan_sendmsg(chan, msg, flags, overhead); } static ssize_t chan_prepare_sendmsg(lc_channel_t *chan, struct msghdr *msg, int flags, ssize_t overhead) { const int hdrs = 1; struct iovec iov[msg->msg_iovlen + hdrs + 1]; const size_t iovlen = sizeof iov / sizeof iov[0]; unsigned char sig[crypto_sign_BYTES]; if (chan->bps_out) chan_ratelimit(chan); if (chan->token) { if (!chan->ssk.key) return (errno = ENOKEY), -1; /* prepend token */ iov[0].iov_base = chan->token; iov[0].iov_len = sizeof(lc_token_t); /* append buffer for msg signature */ iov[iovlen - 1].iov_base = sig; iov[iovlen - 1].iov_len = sizeof sig; /* sign message (including token) */ crypto_sign_state state; crypto_sign_init(&state); crypto_sign_update(&state, iov[0].iov_base, iov[0].iov_len); for (int i = 0; i < (int)msg->msg_iovlen; i++) { iov[i + hdrs].iov_base = msg->msg_iov[i].iov_base; iov[i + hdrs].iov_len = msg->msg_iov[i].iov_len; crypto_sign_update(&state, iov[i + hdrs].iov_base, iov[i + hdrs].iov_len); } if (crypto_sign_final_create(&state, sig, NULL, chan->ssk.key) == -1) { return (errno = ENOTRECOVERABLE), -1; } msg->msg_iov = iov; msg->msg_iovlen = iovlen; overhead += sizeof(lc_token_t) + sizeof sig; } if (chan->sock->type == LC_SOCK_IN6) { msg->msg_name = (struct sockaddr *)&chan->sa; msg->msg_namelen = sizeof(struct sockaddr_in6); } else if (chan->sock->type == LC_SOCK_PAIR) { if (lc_socket_oil_cmp(chan->sock, chan->hash)) return 0; return chan_sendmsg_tlv(chan, msg, flags, overhead); } if (!chan->sock->ifx) return chan_sendmsg_unbound(chan, msg, flags); return chan_sendmsg(chan, msg, flags, overhead); } static ssize_t chan_send(lc_channel_t *chan, const void *buf, size_t len, int flags, ssize_t ohead) { struct iovec iov = { .iov_base = (void * const)buf, .iov_len = len}; struct msghdr msg = { .msg_iov = &iov, .msg_iovlen = 1 }; return chan_prepare_sendmsg(chan, &msg, flags, ohead); } #ifdef HAVE_LIBLCRQ #ifdef HAVE_LIBSODIUM #define OH_SYMM crypto_secretbox_MACBYTES + crypto_secretbox_NONCEBYTES #if HAVE_RQ_OTI #define OH_OTI sizeof(rq_oti_t) + sizeof(rq_scheme_t) #endif static unsigned char *encrypt_buffer(lc_channel_t *chan, const void *buf, size_t len) { size_t elen = len + OH_SYMM; unsigned char *ebuf; unsigned char *nonce; ebuf = malloc(elen); if (!ebuf) return NULL; nonce = ebuf + len + crypto_secretbox_MACBYTES; randombytes_buf(nonce, crypto_secretbox_NONCEBYTES); crypto_secretbox_easy(ebuf, buf, len, nonce, chan->key.key); return ebuf; } #endif static ssize_t channel_send_coded_rq(lc_channel_t *chan, const void *buf, size_t len, int flags) { static ssize_t ohead; uint32_t esi = 0; uint8_t sbn = 0; rq_pid_t pid = 0; if (buf || !chan->rq) { /* new data, encode */ unsigned char *data = (unsigned char *)buf; unsigned char *ebuf = NULL; if (chan->rq) rq_free(chan->rq); /* new data, free old rq ctx */ hash_generic(chan->oid[0].hash, HASHSIZE, (void *)buf, len); ohead = HASHSIZE; /* OID */ #if HAVE_RQ_OTI if (chan->coding & LC_CODE_FEC_OTI) ohead += OH_OTI; #endif chan->pid = pid; #ifdef HAVE_LIBSODIUM if (chan->coding & LC_CODE_SYMM) { ebuf = encrypt_buffer(chan, buf, len); if (!ebuf) return -1; data = ebuf; len += OH_SYMM; ohead += OH_SYMM; } #endif chan->rq = rq_init(len, chan->T); if (!chan->rq) return -1; if (rq_encode(chan->rq, data, len)) return -1; free(ebuf); } else { pid = chan->pid; sbn = rq_pid2sbn(pid); esi = rq_pid2esi(pid); if (!chan->rq) return -1; /* no rq object */ if ((uint32_t)(rq_KP(chan->rq) + RQ_OVERHEAD * 2) == ++esi) { esi = 0; if (rq_Z(chan->rq) == ++sbn) sbn = 0; } pid = rq_pidset(sbn, esi); chan->pid = pid; } /* send next symbol */ struct iovec iov[7]; struct msghdr msg = { .msg_iov = iov, }; uint8_t sym[chan->T]; const int rqf = ((chan->coding & LC_CODE_FEC_RAND) || esi >= rq_K(chan->rq)) ? RQ_RAND : 0; int v = 0; /* prepend OID */ iov[v].iov_base = chan->oid[0].hash; iov[v++].iov_len = HASHSIZE; #if HAVE_RQ_OTI rq_oti_t oti = 0; rq_scheme_t scheme = 0; if (chan->coding & LC_CODE_FEC_OTI) { rq_oti(chan->rq, &oti, &scheme); iov[v].iov_base = &oti; iov[v++].iov_len = sizeof oti; iov[v].iov_base = &scheme; iov[v++].iov_len = sizeof scheme; } #endif iov[v].iov_base = &pid; iov[v++].iov_len = sizeof pid; iov[v].iov_base = sym; iov[v++].iov_len = sizeof sym; msg.msg_iovlen = v; rq_symbol(chan->rq, &pid, sym, rqf); return chan_prepare_sendmsg(chan, &msg, flags, ohead); } #endif #ifdef HAVE_LIBSODIUM static ssize_t channel_send_symm(lc_channel_t *chan, const void *buf, size_t len, int flags) { const size_t elen = len + crypto_secretbox_MACBYTES + crypto_secretbox_NONCEBYTES; unsigned char ebuf[elen]; unsigned char *sbuf = (unsigned char *)buf; ssize_t ohead = 0; memset(ebuf, 0, elen); if (buf && (chan->coding & LC_CODE_SYMM)) { unsigned char *nonce = ebuf + len + crypto_secretbox_MACBYTES; randombytes_buf(nonce, crypto_secretbox_NONCEBYTES); crypto_secretbox_easy(ebuf, sbuf, len, nonce, chan->key.key); sbuf = ebuf; ohead += crypto_secretbox_MACBYTES + crypto_secretbox_NONCEBYTES; } return chan_send(chan, sbuf, elen, flags, ohead); } #endif #ifdef HAVE_LIBLCRQ static void channel_free_rq(lc_channel_t *chan) { chan->orig = 0; chan->syms = 0; if (chan->rq_blk) { free (chan->rq_blk); chan->rq_blk = NULL; } if (chan->ESI) { free(chan->ESI); chan->ESI = NULL; } rq_free(chan->rq); chan->rq = NULL; } #endif ssize_t lc_channel_send(lc_channel_t *chan, const void *buf, size_t len, int flags) { if (chan->coding & LC_CODE_FEC_RQ) { #ifdef HAVE_LIBLCRQ ssize_t rc = channel_send_coded_rq(chan, buf, len, flags); if (rc >= 0 && chan->rq_oh >= 0) { const int pkts = rq_KP(chan->rq) + chan->rq_oh; ssize_t byt = rc; for (int i = 1; i < pkts; i++) { rc = channel_send_coded_rq(chan, NULL, 0, flags); if (rc < 0) return rc; byt += rc; } rc = rq_F(chan->rq); /* return nett bytes */ if (chan->coding & LC_CODE_SYMM) rc -= OH_SYMM; } return rc; #else return (errno = ENOTSUP), -1; #endif } if (chan->coding & LC_CODE_SYMM) { #ifdef HAVE_LIBSODIUM return channel_send_symm(chan, buf, len, flags); #else return (errno = ENOTSUP), -1; #endif } return chan_send(chan, buf, len, flags, 0); } /* gather up msg parts into a single buffer for encoding */ static ssize_t channel_send_gather(lc_channel_t *chan, struct msghdr *msg, const size_t len, int flags) { char buf[len]; char *ptr = buf; for (int i = 0; i < (int)msg->msg_iovlen; i++) { memcpy(ptr, msg->msg_iov[i].iov_base, msg->msg_iov[i].iov_len); ptr += msg->msg_iov[i].iov_len; } return lc_channel_send(chan, buf, len, flags); } static ssize_t channel_send_encoded(lc_channel_t *chan, struct msghdr *msg, int flags) { size_t len = 0; if (!msg) return lc_channel_send(chan, NULL, len, flags); for (int i = 0; i < (int)msg->msg_iovlen; i++) { len += msg->msg_iov[i].iov_len; } return channel_send_gather(chan, msg, len, flags); } ssize_t lc_channel_sendmsg(lc_channel_t *chan, struct msghdr *msg, int flags) { if (chan->coding) return channel_send_encoded(chan, msg, flags); return chan_prepare_sendmsg(chan, msg, flags, 0); } ssize_t lc_socket_sendmsg(lc_socket_t *sock, struct msghdr *msg, int flags) { ssize_t bytes = 0, rc = -1; if (!pthread_mutex_lock(&sock->ctx->mtx)) { for (lc_channel_t *chan = sock->ctx->chan_list; chan; chan = chan->next) { pthread_mutex_unlock(&sock->ctx->mtx); if (chan->sock == sock) { if ((rc = lc_channel_sendmsg(chan, msg, flags)) >= 0) { bytes += rc; } else return -1; } if (pthread_mutex_lock(&sock->ctx->mtx)) return -1; } pthread_mutex_unlock(&sock->ctx->mtx); } return (rc >= 0) ? bytes : -1; } ssize_t lc_socket_send(lc_socket_t *sock, const void *buf, size_t len, int flags) { struct iovec iov = { .iov_base = (void * const)buf, .iov_len = len}; struct msghdr msg = { .msg_iov = &iov, .msg_iovlen = 1 }; return lc_socket_sendmsg(sock, &msg, flags); } int lc_channel_nack_handler_thr(lc_channel_t *chan, int n_seconds, void *(*nack_thread)(void *)) { pthread_attr_t attr; pthread_mutexattr_t mutexattr; int saveerrno; lc_channel_logging_t *logging = calloc(1, sizeof(lc_channel_logging_t)); if (! logging) return -1; logging->chan_nack = lc_channel_sidehash(chan, (void *)SIDE_CHANNEL_NACK, strlen(SIDE_CHANNEL_NACK)); if (! logging->chan_nack) goto error; logging->sock_nack = lc_socket_new(chan->ctx); if (! logging->sock_nack) goto error; lc_channel_bind(logging->sock_nack, logging->chan_nack); if (lc_channel_join(logging->chan_nack)) goto error; logging->chan_data = chan; logging->n_seconds = n_seconds; if (chan->logging) lc_close_nack_logger(chan->logging); chan->logging = logging; pthread_mutexattr_init(&mutexattr); pthread_mutex_init(&logging->mutex, &mutexattr); pthread_mutexattr_destroy(&mutexattr); logging->oldest = NULL; logging->newest = NULL; pthread_attr_init(&attr); pthread_create(&logging->nack_thread, &attr, nack_thread, logging); pthread_attr_destroy(&attr); return 0; error: saveerrno = errno; if (logging->chan_nack) lc_channel_free(logging->chan_nack); if (logging->sock_nack) lc_socket_close(logging->sock_nack); free(logging); errno = saveerrno; return -1; } static void *nack_thread(void * _logging) { lc_channel_logging_t * logging = _logging; pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); while (1) { /* wait for a NACK request for up to a second; if one arrives, process it; * also go through the list of logged messages to see if anything needs * to be removed */ struct pollfd pfd = { .fd = logging->sock_nack->sock, .events = POLLIN, }; lc_packet_log_t *oldest = aload(&logging->oldest); lc_packet_log_t *newest; int ok; ok = poll(&pfd, 1, 1000); if (ok > 0) { pthread_mutex_lock(&logging->mutex); /* process this request */ uint64_t nack; lc_seq_t seq; if (lc_socket_recv(logging->sock_nack, &nack, sizeof(nack), 0) == -1) break; seq = be64toh(nack); /* see if we have this to resend */ oldest = aload(&logging->oldest); newest = aload(&logging->newest); if (oldest && oldest->seq <= seq && seq <= newest->seq) { /* the message may be in the list, and we exit the critical section * now as the only thing other thread may do is to add entries after * logging->newest and we are going to make sure we don't look there; * this improves performance for the other threads if the list gets * very long */ lc_packet_log_t * end = newest, * msg = NULL; /* find this message in the list */ msg = oldest; while (msg && msg->seq < seq && msg != end) msg = msg->next; /* MUST unlock before lc_channel_send() */ pthread_mutex_unlock(&logging->mutex); /* if found, resend it (no point checking return * of lc_channel_send() here, as nowhere to send * error. Just continue. */ if (msg && msg->seq == seq) lc_channel_send(logging->chan_data, msg->data, msg->len, 0); } else pthread_mutex_unlock(&logging->mutex); } pthread_mutex_lock(&logging->mutex); oldest = aload(&logging->oldest); if (oldest) { time_t expire; expire = time(NULL) - logging->n_seconds; while (oldest && oldest->time < expire) { lc_packet_log_t * go = oldest; oldest = aload(&go->next); if (!oldest) astor(&logging->newest, NULL); free(go); oldest = aload(&logging->oldest); } } pthread_mutex_unlock(&logging->mutex); } return NULL; } int lc_channel_nack_handler(lc_channel_t *chan, int n_seconds) { return lc_channel_nack_handler_thr(chan, n_seconds, nack_thread); } static int lc_channel_logmsg(lc_channel_logging_t *logging, const void *buf, size_t len, lc_seq_t seq) { lc_packet_log_t * msg; msg = calloc(1, sizeof(lc_packet_log_t) + len); if (! msg) return -1; msg->next = NULL; msg->len = len; msg->time = time(NULL); msg->seq = seq; memcpy(msg->data, buf, len); pthread_mutex_lock(&logging->mutex); if (logging->newest) logging->newest->next = msg; else astor(&logging->oldest, msg); astor(&logging->newest, msg); pthread_mutex_unlock(&logging->mutex); return 0; } int lc_channel_nack_add_log(lc_channel_t *chan, const void *buf, size_t len, lc_seq_t seq) { if (chan && chan->logging) return lc_channel_logmsg(chan->logging, buf, len, seq); else return 0; } ssize_t lc_msg_sendto(int sock, const void *buf, size_t len, struct sockaddr_in6 *sa, int flags) { if (flags & MSG_DROP) return len; return sendto(sock, buf, len, flags, (struct sockaddr *)sa, sizeof(struct sockaddr_in6)); } ssize_t lc_msg_send(lc_channel_t *chan, lc_message_t *msg) { lc_message_head_t *head = NULL; char *buf = NULL; size_t len = 0; size_t ohead = 0; ssize_t bytes = 0; struct timespec t = {0}; int state = 0; int err = 0; if (!chan->sock) return LC_ERROR_SOCKET_REQUIRED; if (msg->len > 0 && !msg->data) return LC_ERROR_MESSAGE_EMPTY; pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &state); head = calloc(1, sizeof(lc_message_head_t)); if (!head) return LC_ERROR_MALLOC; if (msg->timestamp) head->timestamp = htobe64(msg->timestamp); else if (!clock_gettime(CLOCK_REALTIME, &t)) head->timestamp = htobe64(t.tv_sec * 1000000000 + t.tv_nsec); head->seq = htobe64(add_fetch(&chan->seq, 1)); lc_getrandom(&head->rnd, sizeof(lc_rnd_t)); head->len = htobe64(msg->len); head->op = msg->op; len = msg->len; if (chan->coding & LC_CODE_SYMM) { #ifdef HAVE_LIBSODIUM ohead = crypto_secretbox_MACBYTES + crypto_secretbox_NONCEBYTES; #else free(head); return (errno = ENOTSUP), -1; #endif } buf = calloc(1, sizeof(lc_message_head_t) + len + ohead); if (!buf) { free(head); return LC_ERROR_MALLOC; } memcpy(buf, head, sizeof(lc_message_head_t)); if (msg->data) memcpy(buf + sizeof(lc_message_head_t), msg->data, len); len += sizeof(lc_message_head_t); if (chan->coding & LC_CODE_SYMM) { #ifdef HAVE_LIBSODIUM unsigned char *nonce; nonce = (unsigned char *)buf + len + crypto_secretbox_MACBYTES; randombytes_buf(nonce, crypto_secretbox_MACBYTES); crypto_secretbox_easy((unsigned char *)buf, (unsigned char *)buf, len, nonce, chan->key.key); #endif } if (chan->logging) /* chan->seq could have been changed by another thread in the meantime, * so use head->seq which we know hasn't */ lc_channel_logmsg(chan->logging, buf, len + ohead, be64toh(head->seq)); bytes = chan_send(chan, buf, len + ohead, 0, 0); if (bytes == -1) err = errno; free(head); free(buf); pthread_setcancelstate(state, NULL); if (err) errno = err; return bytes; } #ifndef IPV6_MULTICAST_ALL static int lc_socket_group_joined(lc_socket_t *sock, struct in6_addr *grp) { for (lc_grplist_t *g = sock->grps; g; g = g->next) { if (!memcmp(&g->grp, grp, sizeof(struct in6_addr))) return 1; } return 0; } #endif lc_channel_t *lc_channel_by_address(lc_ctx_t *lctx, struct in6_addr *addr) { lc_channel_t *p = NULL; if (!pthread_mutex_lock(&lctx->mtx)) { for (p = lctx->chan_list; p; p = p->next) { if (!memcmp(addr,& p->sa.sin6_addr, sizeof(struct in6_addr))) break; } pthread_mutex_unlock(&lctx->mtx); } if (!p) errno = ENOENT; return p; } lc_channel_t *lc_socket_channel_by_address(lc_socket_t *sock, struct in6_addr *addr) { lc_ctx_t *lctx = lc_socket_ctx(sock); lc_channel_t *p = NULL; if (!pthread_mutex_lock(&lctx->mtx)) { for (p = aload(&lctx->chan_list); p; p = aload(&p->next)) { if (aload(&p->sock) != sock) continue; if (!memcmp(addr,& p->sa.sin6_addr, sizeof(struct in6_addr))) break; } pthread_mutex_unlock(&lctx->mtx); } if (!p) errno = ENOENT; return p; } lc_channel_t *lc_channel_by_hash(lc_ctx_t *lctx, unsigned char *hash, size_t hashlen) { lc_channel_t *p = NULL; if (!pthread_mutex_lock(&lctx->mtx)) { for (p = lctx->chan_list; p; p = p->next) { if (!memcmp(p->hash, hash, hashlen)) break; } pthread_mutex_unlock(&lctx->mtx); } if (!p) errno = ENOENT; return p; } /* return channel which matches both the socket and hash */ lc_channel_t *lc_channel_socket_by_hash(lc_socket_t *sock, unsigned char *hash, size_t hashlen) { lc_ctx_t *lctx = sock->ctx; lc_channel_t *p = NULL; if (!pthread_mutex_lock(&lctx->mtx)) { for (p = lctx->chan_list; p; p = p->next) { if (p->sock != sock) continue; if (!memcmp(p->hash, hash, hashlen)) break; } pthread_mutex_unlock(&lctx->mtx); } if (!p) errno = ENOENT; return p; } #ifdef HAVE_LIBSODIUM static ssize_t lc_channel_decoded(lc_channel_t *chan, unsigned char *m, unsigned char *c, size_t bytes) { size_t clen = bytes - crypto_secretbox_NONCEBYTES; size_t mlen = clen - crypto_secretbox_MACBYTES; unsigned char *nonce = c + clen; if (bytes < crypto_secretbox_NONCEBYTES + crypto_secretbox_MACBYTES + 1) return (errno = EMSGSIZE), -1; if (crypto_secretbox_open_easy(m, c, clen, nonce, chan->key.key)) return (errno = EBADMSG), -1; return mlen; } #endif #ifdef HAVE_LINUX_NETLINK_H static void handle_netlink_msg(lc_socket_t *sock, struct nlmsghdr *msg) { struct ifinfomsg *ifi = NLMSG_DATA(msg); char ifname[IF_NAMESIZE]; lc_ctx_t *lctx = sock->ctx; if (msg->nlmsg_type != RTM_NEWLINK) return; /* new link detected, JOIN channels */ if_indextoname(ifi->ifi_index, ifname); if (!pthread_mutex_lock(&lctx->mtx)) { for (lc_channel_t *p = lctx->chan_list; p; p = p->next) { if (p->sock != sock) continue; lc_channel_join(p); } pthread_mutex_unlock(&lctx->mtx); } } /* handle netlink event */ static int recv_netlink_event(lc_socket_t *sock, int fd, struct sockaddr_nl *sa) { struct nlmsghdr buf[8192/sizeof(struct nlmsghdr)]; struct iovec iov = { buf, sizeof(buf) }; struct msghdr msg = { sa, sizeof(*sa), &iov, 1, NULL, 0, 0 }; struct nlmsghdr *nh; ssize_t len; len = recvmsg(fd, &msg, 0); if (len == -1) return -1; for (nh = (struct nlmsghdr *)buf; NLMSG_OK(nh, len); nh = NLMSG_NEXT(nh, len)) { if (nh->nlmsg_type == NLMSG_DONE) break; /* end of multipart message */ if (nh->nlmsg_type == NLMSG_ERROR) return -1; else handle_netlink_msg(sock, nh); } return 0; } #endif static ssize_t socket_recvmsg(lc_socket_t *sock, struct msghdr *msg, int flags) { enum { FD_NETLNK, FD_SOCKET }; int fd = sock->sock; #ifdef HAVE_LINUX_NETLINK_H /* for IPv6 sockets which aren't bound, watch netlink */ if (!sock->ifx && sock->type == LC_SOCK_IN6) { const nfds_t nfds = 2; struct pollfd fds[nfds]; struct sockaddr_nl sa = { .nl_family = AF_NETLINK, .nl_groups = RTMGRP_LINK }; int nlfd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); if (nlfd == -1) return -1; if (bind(nlfd, (struct sockaddr *) &sa, sizeof(sa))) return -1; fds[FD_NETLNK].fd = nlfd; fds[FD_NETLNK].events = POLLIN; fds[FD_SOCKET].fd = sock->sock; fds[FD_SOCKET].events = POLLIN; for (;;) { fd = poll(fds, nfds, -1); if (fd == -1) return -1; if (fds[FD_NETLNK].revents) { if (recv_netlink_event(sock, nlfd, &sa)) return -1; } if (fds[FD_SOCKET].revents) { fd = fds[FD_SOCKET].fd; break; } } close(nlfd); } #endif return recvmsg(fd, msg, flags); } ssize_t lc_msg_recv(lc_socket_t *sock, lc_message_t *msg) { ssize_t zi = 0; struct iovec iov[1]; struct msghdr msgh = {0}; struct in6_pktinfo pi = {0}; struct sockaddr_in6 from; unsigned char buf[BUFSIZ]; struct cmsghdr *cmsg; char ctl[CMSG_SPACE(sizeof(struct in6_pktinfo))]; lc_message_head_t head; lc_channel_t *chan = NULL; int opt = 1; #ifndef IPV6_MULTICAST_ALL recv_again: #endif iov[0].iov_base = buf; iov[0].iov_len = sizeof buf; msgh.msg_control = ctl; msgh.msg_controllen = sizeof ctl; msgh.msg_name = &from; msgh.msg_namelen = sizeof from; msgh.msg_iov = iov; msgh.msg_iovlen = 1; if (setsockopt(sock->sock, IPPROTO_IPV6, IPV6_RECVPKTINFO, &opt, sizeof opt) == -1) return -1; pthread_testcancel(); if ((zi = socket_recvmsg(sock, &msgh, 0)) <= 0) return zi; for (cmsg = CMSG_FIRSTHDR(&msgh); cmsg; cmsg = CMSG_NXTHDR(&msgh, cmsg)) { if (cmsg->cmsg_type == IPV6_PKTINFO) { /* may not be aligned, copy */ memcpy(&pi, CMSG_DATA(cmsg), sizeof(struct in6_pktinfo)); /* if we have a channel, we can use it for gap detection */ chan = lc_channel_by_address(sock->ctx, &pi.ipi6_addr); #ifndef IPV6_MULTICAST_ALL /* destination is group we haven't joined - drop it */ if (!lc_socket_group_joined(sock, &pi.ipi6_addr)) goto recv_again; #endif break; } } if (sock->ccoding & LC_CODE_SYMM) { #ifdef HAVE_LIBSODIUM chan = lc_channel_by_address(sock->ctx, &pi.ipi6_addr); if (!chan) return -1; zi = lc_channel_decoded(chan, buf, buf, zi); #else return (errno = ENOTSUP), -1; #endif } if (lc_msg_init_size(msg, (size_t)zi - sizeof(lc_message_head_t)) == -1) return -1; memcpy(&head, buf, sizeof(lc_message_head_t)); msg->dst = pi.ipi6_addr; msg->src = (&from)->sin6_addr; msg->seq = be64toh(head.seq); msg->rnd = be64toh(head.rnd); msg->timestamp = be64toh(head.timestamp); msg->op = head.op; if (chan && chan->gap_detect) do_gap_detection(chan->gap_detect, msg->seq); if (zi > (ssize_t)sizeof(lc_message_head_t)) { memcpy(msg->data, buf + sizeof(lc_message_head_t), msg->len); } return zi; } int lc_socket_listen_cancel(lc_socket_t *sock) { if (sock->thread) { if (pthread_cancel(sock->thread)) return LC_ERROR_THREAD_CANCEL; if (pthread_join(sock->thread, NULL)) return LC_ERROR_THREAD_JOIN; sock->thread = 0; } return 0; } static void lc_op_pong_handler(lc_socket_call_t *sc, lc_message_t *msg) { if (sc->callback_msg) sc->callback_msg(msg); } static void lc_op_ping_handler(lc_socket_call_t *sc, lc_message_t *msg) { (void) sc; /* unused */ int opt = LC_OP_PONG; /* received PING, echo PONG back to same channel */ lc_msg_set(msg, LC_ATTR_OPCODE, &opt); lc_msg_send(msg->chan, msg); } static void lc_op_data_handler(lc_socket_call_t *sc, lc_message_t *msg) { /* callback to message handler */ if (sc->callback_msg) sc->callback_msg(msg); } static ssize_t lc_socket_recvmsg_if(lc_socket_t *sock, struct msghdr *msg, int flags, struct in6_pktinfo *pi, lc_channel_t **dst) { char ctl[CMSG_SPACE(sizeof(struct in6_pktinfo))]; struct cmsghdr *cmsg; ssize_t bytes; int opt = 1; /* We're only interested in packets arriving on the socket->ifx * interface. If we bind to an interface-specific address, we will get no * multicast packets. If bound to either INADDR_ANY or the multicast * group address, we receive packets on all interfaces. So, we need to * filter by extracting the receiving interface from ancillary data */ if (sock->type == LC_SOCK_IN6) { if (setsockopt(sock->sock, IPPROTO_IPV6, IPV6_RECVPKTINFO, &opt, sizeof opt) == -1) return -1; /* provide control buffer if caller hasn't */ if (!msg->msg_control) { msg->msg_control = ctl; msg->msg_controllen = sizeof ctl; } } recv_again: for (;;) { bytes = socket_recvmsg(sock, msg, flags); if (bytes == -1) return -1; if (sock->type != LC_SOCK_IN6) { if (dst) { lc_tlv_hash_t *tlv = msg->msg_iov[0].iov_base; *dst = lc_channel_socket_by_hash(sock, tlv->value, sizeof tlv->value); } return bytes; } for (cmsg = CMSG_FIRSTHDR(msg); cmsg; cmsg = CMSG_NXTHDR(msg, cmsg)) { if (cmsg->cmsg_type == IPV6_PKTINFO) { memcpy(pi, CMSG_DATA(cmsg), sizeof(struct in6_pktinfo)); #ifndef IPV6_MULTICAST_ALL if (!lc_socket_group_joined(sock, &pi->ipi6_addr)) { if (flags & MSG_PEEK) { /* read & drop packet */ int beijing = flags^MSG_PEEK; recvmsg(sock->sock, msg, beijing); } } else #endif if (!sock->ifx || sock->ifx == pi->ipi6_ifindex) { if (sock->chan_active || dst) { lc_channel_t *chan; chan = lc_socket_channel_by_address(sock, &pi->ipi6_addr); if (dst) *dst = chan; if (sock->chan_active) { /* for lc_channel_* calls, check channel */ if (chan != sock->chan_active) { if (flags & MSG_DROP) goto recv_again; return (errno = ECHRNG), -1; } } } return bytes; } else break; } } } /* not reached */ } static ssize_t scatter_msg_parts(unsigned char *buf, size_t len, struct msghdr *msg, ssize_t rc) { unsigned char *ptr = buf; for (int v = 0; v < (int)msg->msg_iovlen; v++) { memcpy(msg->msg_iov[v].iov_base, ptr, MIN(msg->msg_iov[v].iov_len, len)); ptr += msg->msg_iov[v].iov_len; len -= msg->msg_iov[v].iov_len; } return rc; } #ifdef HAVE_LIBLCRQ static int lc_channel_rq_init(lc_channel_t *chan, size_t len) { if (!chan->rq) chan->rq = rq_init(len, chan->T); if (!chan->rq) return -1; if (!chan->rq_blk) { /* alloc ESI + symbol buffer */ const uint16_t Z = rq_Z(chan->rq); const uint16_t nesi = rq_KP(chan->rq) + RQ_OVERHEAD; const uint32_t M = nesi * (uint32_t)Z; chan->ESI = calloc(Z, nesi * sizeof(uint32_t)); if (!chan->ESI) goto err_free_rq; memset(chan->ESI, ~0, M * sizeof(uint32_t)); chan->rq_blk = calloc(Z, (size_t)nesi * chan->T); if (!chan->rq_blk) goto err_free_ESI; if (chan->syms == 0) chan->orig = rq_K(chan->rq); } return 0; err_free_ESI: free(chan->ESI); chan->ESI = NULL; err_free_rq: rq_free(chan->rq); chan->rq = NULL; return -1; } static int set_oid_status_done(lc_channel_t *chan, unsigned char *oid) { const int oidlen = sizeof chan->oid / sizeof chan->oid[0]; int idx = -1; for (int i = 0; i < oidlen; i++) { if (!memcmp(oid, chan->oid[i].hash, HASHSIZE)) { idx = i; break; } } if (idx == -1) return -1; chan->oid[idx].status = 1; /* done */ return 0; } static ssize_t decode_buffer(lc_channel_t *chan, struct msghdr *msg, unsigned char *buf, ssize_t len) { len = lc_channel_decoded(chan, buf, buf, len); if (len == -1) return -1; return scatter_msg_parts(buf, len, msg, len); } static ssize_t channel_rq_decode_blocks(lc_channel_t *chan, struct msghdr *msg, unsigned char *buf, size_t len) { const uint16_t OH = RQ_OVERHEAD; const uint16_t KP = rq_KP(chan->rq); const uint16_t K = rq_K(chan->rq); const uint16_t Z = rq_Z(chan->rq); const uint16_t T = rq_T(chan->rq); const uint16_t nesi = KP + OH; ssize_t zi = rq_F(chan->rq); size_t blocksz = (uint32_t)T * K; size_t sz = len; uint8_t *dec = buf, *enc = chan->rq_blk; if (chan->filter) sz -= sizeof(lc_token_t); for (uint8_t sbn = 0; sbn < Z; sbn++) { if (!chan->orig) memcpy(dec, enc, MIN(sz, blocksz)); /* original symbols, no decoding */ else { if (sz < blocksz) { uint8_t * temp = malloc(blocksz); if (! temp) { zi = -1; break; } if (rq_decode(chan->rq, temp, enc, ESIr(sbn), nesi) == -1) { zi = -1; break; } memcpy(dec, temp, sz); free(temp); } else { if (rq_decode(chan->rq, dec, enc, ESIr(sbn), nesi) == -1) { zi = -1; break; } } } dec += blocksz; enc += blocksz; sz -= blocksz; } channel_free_rq(chan); if (chan->coding & LC_CODE_SYMM) return decode_buffer(chan, msg, buf, zi); return scatter_msg_parts(buf, len, msg, zi); } /* if oid \notin chan->oid: * - Append(chan->oid, oid) * - oid.status = 0; * - return 0 (ok) * if oid \in chan->oid: * if oid.status == 1 return -1, EAGAIN (drop packet) * else return 0 (ok) */ static int check_oid(lc_channel_t *chan, unsigned char *oid) { const int oidlen = sizeof chan->oid / sizeof chan->oid[0]; int idx = -1; for (int i = 0; i < oidlen; i++) { if (!memcmp(oid, chan->oid[i].hash, HASHSIZE)) { idx = i; break; } } if (idx == -1) { /* new object */ chan->oid_cur = (chan->oid_cur + 1) % oidlen; chan->oid[chan->oid_cur].status = 0; memcpy(chan->oid[chan->oid_cur].hash, oid, HASHSIZE); return 0; } if (chan->oid[idx].status) { /* we've processed this object, drop */ channel_free_rq(chan); return (errno = EAGAIN), -1; } return 0; } /* store the received symbol: * - if ESI < K, store at blk[sbn][esi] * - if ESI >= K, store in next available repair slot >= K * - if ESI >= K and all slots >= K used, backfill K * - update bitmap, ESI list * - if received symbols >= KP + OH, decode and return */ static ssize_t channel_msg_decode(lc_channel_t *chan, struct msghdr *msg, uint8_t *oidbuf, size_t len) { const uint64_t F = rq_F(chan->rq); const uint16_t OH = RQ_OVERHEAD; const uint16_t KP = rq_KP(chan->rq); const uint16_t K = rq_K(chan->rq); const uint16_t Z = rq_Z(chan->rq); const uint16_t T = rq_T(chan->rq); const uint16_t nesi = KP + OH; const uint32_t M = nesi * (uint32_t)Z; unsigned char *oid = oidbuf; uint8_t *buf = oidbuf + HASHSIZE; uint8_t *sym = buf + sizeof(rq_pid_t); uint8_t sbn; uint32_t esi; rq_pid_t pid = *(rq_pid_t *)(buf); rq_oti_t oti = 0; /* rq_scheme_t scheme = 0; */ int idx; if (check_oid(chan, oid)) return -1; #if HAVE_RQ_OTI if (chan->coding & LC_CODE_FEC_OTI) { oti = *(rq_oti_t *)(buf); /* scheme = *(rq_scheme_t *)(buf + sizeof oti); */ pid = *(rq_pid_t *)(buf + OTI_OH); sym += OTI_OH; if (rq_oti_F(oti) != F || rq_oti_T(oti) != T) return (errno = EAGAIN), -1; } #endif sbn = rq_pid2sbn(pid); esi = rq_pid2esi(pid); if (sbn >= Z) return (errno = EAGAIN), -1; if (esi < K) { if (ESI(sbn, esi) == esi) return (errno = EAGAIN), -1; idx = esi; chan->orig--; } else for (idx = nesi - 1; idx; idx--) { if (ESI(sbn, idx) == esi) return (errno = EAGAIN), -1; if (ESI(sbn, idx) == UINT32_MAX) break; } if (ESI(sbn, idx) == UINT32_MAX) { chan->syms++; ESI(sbn, idx) = esi; memcpy(BLK(sbn, idx), sym, T); } if (chan->orig && chan->syms < M) return (errno = EAGAIN), -1; set_oid_status_done(chan, oid); return channel_rq_decode_blocks(chan, msg, oidbuf, len); } #endif #ifdef HAVE_LIBSODIUM static ssize_t channel_msg_decrypt(lc_channel_t *chan, struct msghdr *msg, unsigned char *buf, size_t len) { const size_t clen = len - crypto_secretbox_NONCEBYTES; unsigned char *nonce = buf + clen; unsigned char *ptr; ssize_t rc = len - crypto_secretbox_NONCEBYTES - crypto_secretbox_MACBYTES; size_t off = (chan->coding & LC_CODE_FEC_RQ) ? HASHSIZE : 0; if (chan->coding & LC_CODE_FEC_OTI) off += OTI_OH; ptr = buf + off; if (len < crypto_secretbox_NONCEBYTES + crypto_secretbox_MACBYTES + 1) return (errno = EMSGSIZE), -1; if (crypto_secretbox_open_easy(ptr, ptr, clen - off, nonce, chan->key.key)) return (errno = EBADMSG), -1; return scatter_msg_parts(ptr, len, msg, rc); } static int channel_filter_check(lc_filter_t *filter, lc_token_t *token, uint8_t *key, unsigned char *sig, unsigned char *payload, size_t len) { /* check token signature */ if (crypto_sign_verify_detached(token->sig, (unsigned char *)token, 64, key) != 0) { return (errno = EPROTO), -1; } /* check message sig */ crypto_sign_state state; crypto_sign_init(&state); crypto_sign_update(&state, payload, len); if (crypto_sign_final_verify(&state, sig, token->bearkey) != 0) { return (errno = EBADMSG), -1; } /* check capbits */ if ((token->capbits & filter->capbits) != filter->capbits) { return (errno = EACCES), -1; } /* check expiry */ if (token->expires) { struct timespec now; if (clock_gettime(CLOCK_REALTIME, &now) == -1) return -1; if ((uint64_t)now.tv_sec > token->expires) return (errno = EKEYEXPIRED), -1; } return 0; } static int channel_filter_drop(lc_channel_t *chan, lc_token_t *token, unsigned char *sig, unsigned char *payload, size_t len) { lc_filter_t *filter = chan->filter; lc_keyring_t *keyring = filter->keyring; if (!keyring) return (errno = ENOKEY), -1; /* find token signer key in filter keyring */ if (keyring->key) { for (size_t n = 0; n < keyring->nkeys; n++) { uint8_t *k = keyring->key[n]; if (!k) return (errno = ENOKEY), -1; if (!memcmp(k, token->signkey, sizeof token->signkey)) { return channel_filter_check(filter, token, k, sig, payload, len); } } } return (errno = EKEYREJECTED), -1; } #endif /* HAVE_LIBSODIUM */ /* recv data prior to encoding */ static ssize_t socket_recvmsg_data(lc_socket_t *sock, struct msghdr *msg, size_t len, int flags, lc_channel_t **dst) { /* provide a buffer large enough to recv encrypted data */ size_t buflen = MAX(len, sock->T) + OTI_OH + HASHSIZE + sizeof(lc_token_t) + crypto_secretbox_NONCEBYTES + crypto_secretbox_MACBYTES + crypto_sign_BYTES; unsigned char *buf; unsigned char *payload; char ctl[CMSG_SPACE(sizeof(struct in6_pktinfo))]; struct in6_pktinfo pi = {0}; struct msghdr emsg = {0}; const int headers = (sock->type == LC_SOCK_IN6) ? 0 : 1; struct iovec iov[2 + headers]; lc_tlv_hash_t tlv_hash; lc_channel_t *chan; ssize_t rc; int v = 0; buf = malloc(buflen); if (!buf) return -1; if (sock->type == LC_SOCK_IN6) { emsg.msg_control = ctl; emsg.msg_controllen = sizeof ctl; } else { iov[v].iov_base = &tlv_hash; iov[v++].iov_len = sizeof tlv_hash; } iov[v].iov_len = buflen; iov[v++].iov_base = buf; emsg.msg_iov = iov; emsg.msg_iovlen = v; recv_again: payload = buf; rc = lc_socket_recvmsg_if(sock, &emsg, flags, &pi, dst); if (rc == -1) goto err_free_buf; if (flags & MSG_PEEK) goto err_free_buf; if (sock->type == LC_SOCK_IN6) { chan = lc_socket_channel_by_address(sock, &pi.ipi6_addr); } else { chan = lc_channel_socket_by_hash(sock, tlv_hash.value, HASHSIZE); if (rc > (ssize_t)sizeof tlv_hash) rc -= sizeof tlv_hash; } if (chan) { #ifdef HAVE_LIBSODIUM if (chan->filter) { lc_token_t *token = (lc_token_t *)payload; unsigned char *sig = payload + rc - crypto_sign_BYTES; size_t plen = rc - crypto_sign_BYTES; if (channel_filter_drop(chan, token, sig, payload, plen)) goto recv_again; rc -= (crypto_sign_BYTES + sizeof(lc_token_t)); payload += sizeof(lc_token_t); } #endif if (!chan->coding) { scatter_msg_parts(payload, rc, msg, rc); goto err_free_buf; } if (chan->coding & LC_CODE_FEC_RQ) { #ifdef HAVE_LIBLCRQ #if HAVE_RQ_OTI ssize_t F = len; if (chan->coding & LC_CODE_SYMM) { F += OH_SYMM, len += OH_SYMM; } if (chan->coding & LC_CODE_FEC_OTI) { rq_oti_t oti; oti = *(rq_oti_t *)(payload + HASHSIZE); /* skip OID */ if (rq_oti_F(oti) > len) return (errno = EMSGSIZE), -1; F = rq_oti_F(oti); } #endif if (lc_channel_rq_init(chan, F) == -1) { rc = -1; goto err_free_buf; } rc = channel_msg_decode(chan, msg, payload, buflen); if (rc == -1) { if (errno == EAGAIN) goto recv_again; goto err_free_buf; } #endif /* HAVE_LIBLCRQ */ } else if (chan->coding & LC_CODE_SYMM) { #ifdef HAVE_LIBSODIUM rc = channel_msg_decrypt(chan, msg, payload, rc); if (rc == -1) goto err_free_buf; #else return (errno = ENOTSUP), -1; #endif } } err_free_buf: free(buf); return rc; } #ifdef HAVE_LIBSODIUM static ssize_t lc_socket_recvmsg_encoded(lc_socket_t *sock, struct msghdr *msg, int flags, lc_channel_t **dst) { size_t len = 0; for (int i = 0; i < (int)msg->msg_iovlen; i++) { len += msg->msg_iov[i].iov_len; } return socket_recvmsg_data(sock, msg, len, flags, dst); } #endif #if !(HAVE_RECVMMSG) /* wrapper for recvmsg for systems with no recvmmsg() - timeout ignored */ static int recvmmsg(int sockfd, struct mmsghdr *msgvec, unsigned int vlen, int flags, struct timespec *timeout) { (void)timeout; /* ignored */ ssize_t rc; int msgs = 0; int waitfor = 0; if (flags & MSG_WAITFORONE) { flags &= ~MSG_WAITFORONE; waitfor = 1; } for (unsigned int u = 0; u < vlen; u++) { rc = recvmsg(sockfd, &msgvec[u].msg_hdr, flags); if (rc == -1) { if (msgs > 0) break; else return -1; } if (waitfor) { flags |= MSG_DONTWAIT; waitfor ^= waitfor; } msgvec[u].msg_len = rc; msgs++; } return msgs; } #endif #ifdef HAVE_LIBSODIUM static int lc_socket_recvmmsg_coded(lc_socket_t *sock, struct mmsghdr *msgvec, unsigned int vlen, int flags, struct timespec *timeout) { (void)timeout; /* ignored */ ssize_t rc; int msgs = 0; int waitfor = 0; if (flags & MSG_WAITFORONE) { flags &= ~MSG_WAITFORONE; waitfor = 1; } for (unsigned int u = 0; u < vlen; u++) { rc = lc_socket_recvmsg_encoded(sock, &msgvec[u].msg_hdr, flags, NULL); if (rc == -1) { if (msgs > 0) break; else return -1; } if (waitfor) { flags |= MSG_DONTWAIT; waitfor ^= waitfor; } msgvec[u].msg_len = rc; msgs++; } return msgs; } #endif int lc_socket_recvmmsg(lc_socket_t *sock, struct mmsghdr *msgvec, unsigned int vlen, int flags, struct timespec *timeout) { if (sock->ccoding & LC_CODE_SYMM) { #ifdef HAVE_LIBSODIUM return lc_socket_recvmmsg_coded(sock, msgvec, vlen, flags, timeout); #else return (errno = ENOTSUP), -1; #endif } return recvmmsg(sock->sock, msgvec, vlen, flags, timeout); } ssize_t lc_socket_multi_recvmsg(lc_socket_t *sock, struct msghdr *msg, int flags, lc_channel_t **dst) { if (sock->ifx || sock->chan_active || dst || sock->ccoding) { size_t len = 0; for (int i = 0; i < (int)msg->msg_iovlen; i++) { len += msg->msg_iov[i].iov_len; } return socket_recvmsg_data(sock, msg, len, flags, dst); } return socket_recvmsg(sock, msg, flags); } ssize_t lc_socket_recvmsg(lc_socket_t *sock, struct msghdr *msg, int flags) { return lc_socket_multi_recvmsg(sock, msg, flags, NULL); } ssize_t lc_socket_multi_recv(lc_socket_t *sock, void *buf, size_t len, int flags, lc_channel_t **dst) { struct iovec iov = { .iov_base = buf, .iov_len = len }; struct msghdr msg = { .msg_iov = &iov, .msg_iovlen = 1 }; return lc_socket_multi_recvmsg(sock, &msg, flags, dst); } ssize_t lc_socket_recv(lc_socket_t *sock, void *buf, size_t len, int flags) { return lc_socket_multi_recv(sock, buf, len, flags, NULL); } /* peek at packet header to get OTI params */ int lc_channel_oti_peek(lc_channel_t *chan, rq_oti_t *oti, rq_scheme_t *scheme) { #if (HAVE_LIBLCRQ && HAVE_RQ_OTI) const size_t sz = ((chan->coding & LC_CODE_SYMM) ? IPV6_MIN_MTU : sizeof *oti + sizeof *scheme) + HASHSIZE; char buf[sz]; ssize_t rc; rc = recv(chan->sock->sock, buf, sz, MSG_PEEK); if (rc >= (ssize_t)(sizeof *oti + sizeof *scheme)) { memcpy(oti, buf + HASHSIZE, sizeof(rq_oti_t)); memcpy(scheme, buf + HASHSIZE + sizeof *oti, sizeof *scheme); if (rq_oti_T(*oti) != chan->T) return (errno = EBADMSG), -1; chan->rq = rq_init(rq_oti_F(*oti), chan->T); } return rc; #else (void)chan, (void)oti, (void) scheme; return (errno = ENOTSUP), -1; #endif } ssize_t lc_channel_recv(lc_channel_t *chan, void *buf, size_t len, int flags) { ssize_t rc; if (!chan || !buf || !len) return (errno = EINVAL), -1; if (!chan->sock) return (errno = ENOTSOCK), -1; chan->sock->chan_active = chan; rc = lc_socket_recv(chan->sock, buf, len, flags); chan->sock->chan_active = NULL; return rc; } static ssize_t channel_recvmsg_encoded(lc_channel_t *chan, struct msghdr *msg, size_t len, int flags) { char buf[len]; char *ptr = buf; ssize_t rc; if ((rc = lc_channel_recv(chan, buf, len, flags)) == -1) return -1; /* scatter parts */ for (int v = 0; v < (int)msg->msg_iovlen; v++) { memcpy(msg->msg_iov[v].iov_base, ptr, msg->msg_iov[v].iov_len); ptr += msg->msg_iov[v].iov_len; } return rc; } ssize_t lc_channel_recvmsg(lc_channel_t *chan, struct msghdr *msg, int flags) { if (!chan->sock) return (errno = ENOTSOCK), -1; if (chan->coding) { size_t len = 0; for (int i = 0; i < (int)msg->msg_iovlen; i++) { len += msg->msg_iov[i].iov_len; } return channel_recvmsg_encoded(chan, msg, len, flags); } chan->sock->chan_active = chan; ssize_t rc = lc_socket_recvmsg(chan->sock, msg, flags); chan->sock->chan_active = NULL; return rc; } static void process_msg(lc_socket_call_t *sc, lc_message_t *msg) { lc_channel_t *chan; inet_ntop(AF_INET6, &msg->dst, msg->dstaddr, INET6_ADDRSTRLEN); inet_ntop(AF_INET6, &msg->src, msg->srcaddr, INET6_ADDRSTRLEN); /* update channel stats */ chan = lc_channel_by_address(sc->sock->ctx, &msg->dst); if (chan) { int (*logger)(lc_channel_t *, lc_message_t *, void *logdb) = aload(&lc_msg_logger); msg->chan = chan; lc_seq_t seq = aload(&chan->seq); astor(&chan->seq, (msg->seq > seq) ? msg->seq + 1 : seq + 1); chan->rnd = msg->rnd; if (logger) logger(chan, msg, NULL); } /* opcode handler */ if (msg->op < LC_OP_MAX && lc_op_handler[msg->op]) lc_op_handler[msg->op](sc, msg); /* callback to message handler */ if (sc->callback_msg) sc->callback_msg(msg); } void *lc_socket_listen_thread(void *arg) { ssize_t len; lc_message_t msg = {0}; lc_socket_call_t *sc = arg; pthread_cleanup_push(free, arg); pthread_cleanup_push(lc_msg_free, &msg); while(1) { len = lc_msg_recv(sc->sock, &msg); if (len > 0) { msg.bytes = len; process_msg(sc, &msg); } if (len < 0) { lc_msg_free(&msg); if (sc->callback_err) sc->callback_err(len); } lc_msg_free(&msg); } /* not reached */ pthread_cleanup_pop(0); pthread_cleanup_pop(0); return NULL; } int lc_socket_listen(lc_socket_t *sock, void (*callback_msg)(lc_message_t*), void (*callback_err)(int)) { pthread_attr_t attr = {0}; lc_socket_call_t *sc; if (!sock) return LC_ERROR_SOCKET_REQUIRED; if (sock->thread) return LC_ERROR_SOCKET_LISTENING; sc = calloc(1, sizeof(lc_socket_call_t)); if (!sc) return LC_ERROR_MALLOC; sc->sock = sock; sc->callback_msg = callback_msg; sc->callback_err = callback_err; pthread_attr_init(&attr); pthread_create(&sock->thread, &attr, &lc_socket_listen_thread, sc); pthread_attr_destroy(&attr); return 0; } static int lc_channel_membership_all(int sock, int opt, struct ipv6_mreq *req) { struct ifaddrs *ifaddr, *ifa; int rc = (opt == IPV6_JOIN_GROUP) ? LC_ERROR_MCAST_JOIN : LC_ERROR_MCAST_PART; if (getifaddrs(&ifaddr) == -1) return -1; for (ifa = ifaddr; ifa; ifa = ifa->ifa_next) { if (!(ifa->ifa_flags & IFF_MULTICAST) || ifa->ifa_addr == NULL || ifa->ifa_addr->sa_family != AF_INET6) continue; req->ipv6mr_interface = if_nametoindex(ifa->ifa_name); if (!setsockopt(sock, IPPROTO_IPV6, opt, req, sizeof(struct ipv6_mreq))) { rc = 0; /* report success if we joined anything */ } } freeifaddrs(ifaddr); return rc; } int lc_socket_oil_cmp(lc_socket_t *sock, unsigned char *hash) { unsigned char *oil = aload(&sock->oil); if (!oil || !hash) goto not_found; for (int h = 0; h < BLOOM_HASHES; h++) { if (!(oil[hash[h] % BLOOM_LEN])) goto not_found; } return 0; not_found: return (errno = ENOENT), -1; } #ifndef IPV6_MULTICAST_ALL static void lc_socket_group_add(lc_socket_t *sock, struct in6_addr *grp) { lc_grplist_t *g, *newgrp; for (g = sock->grps; g; g = g->next) { if (!memcmp(&g->grp, grp, sizeof(struct in6_addr))) return; if (!g->next) break; } newgrp = calloc(1, sizeof(struct lc_grplist_s)); newgrp->grp = *grp; if (!sock->grps) sock->grps = newgrp; else g->next = newgrp; } static void lc_socket_group_del(lc_socket_t *sock, struct in6_addr *grp) { lc_grplist_t *prev = NULL; for (lc_grplist_t *g = sock->grps; g; g = g->next) { if (memcmp(g, grp, sizeof(struct in6_addr)) == 0) { if (prev) { prev->next = (g->next) ? g->next : NULL; } if (g == sock->grps) sock->grps = NULL; free(g); } prev = g; } } #endif int lc_socket_oil_add(lc_socket_t *sock, unsigned char *hash) { const unsigned max = 1 << (CHAR_BIT - 1); if (!sock->oil) { unsigned char *oil = malloc(BLOOM_LEN); if (!oil) return -1; memset(oil, 0, BLOOM_LEN); astor(&sock->oil, oil); } /* if hash not in filter, add it */ if (lc_socket_oil_cmp(sock, hash)) { for (int h = 0; h < BLOOM_HASHES; h++) { unsigned char c = aload(&sock->oil[hash[h] % BLOOM_LEN]); while ((c < max) && !CAE(&sock->oil[hash[h] % BLOOM_LEN], &c, c + 1)); } } return 0; } int lc_socket_oil_del(lc_socket_t *sock, unsigned char *hash) { if (lc_socket_oil_cmp(sock, hash)) return -1; for (int h = 0; h < BLOOM_HASHES; h++) { if (sock->oil[hash[h] % BLOOM_LEN]) sock->oil[hash[h] % BLOOM_LEN]--; } return 0; } static int lc_channel_membership_in6(lc_channel_t *chan, int opt, struct ipv6_mreq *req) { int s = chan->sock->sock; if (opt == IPV6_JOIN_GROUP) { #ifndef IPV6_MULTICAST_ALL lc_socket_group_add(chan->sock, &chan->sa.sin6_addr); #endif lc_socket_oil_add(chan->sock, chan->hash); } else { #ifndef IPV6_MULTICAST_ALL lc_socket_group_del(chan->sock, &chan->sa.sin6_addr); #endif lc_socket_oil_del(chan->sock, chan->hash); } if (chan->sock->ifx) { req->ipv6mr_interface = chan->sock->ifx; return setsockopt(s, IPPROTO_IPV6, opt, req, sizeof(struct ipv6_mreq)); } return lc_channel_membership_all(s, opt, req); } static int lc_channel_action_in6(lc_channel_t *chan, int opt) { struct ipv6_mreq req = {0}; if(!chan->sock) return LC_ERROR_SOCKET_REQUIRED; req.ipv6mr_multiaddr = chan->sa.sin6_addr; return lc_channel_membership_in6(chan, opt, &req); } static int lc_channel_action(lc_channel_t *chan, int opt) { lc_socket_t *sock = chan->sock; if(!chan->sock) return LC_ERROR_SOCKET_REQUIRED; if (chan->sock->type == LC_SOCK_PAIR) sock = sock->pair; if (opt == IPV6_JOIN_GROUP) { lc_socket_oil_add(sock, chan->hash); } else { lc_socket_oil_del(sock, chan->hash); } switch (chan->sock->type) { case LC_SOCK_IN6: return lc_channel_action_in6(chan, opt); case LC_SOCK_PAIR: return 0; default: return (errno = ENOSYS), -1; } } int lc_channel_part(lc_channel_t *chan) { return lc_channel_action(chan, IPV6_LEAVE_GROUP); } int lc_channel_join(lc_channel_t *chan) { return lc_channel_action(chan, IPV6_JOIN_GROUP); } int lc_channel_unbind(lc_channel_t *chan) { chan->sock->bound--; chan->sock = NULL; return 0; } static int lc_socket_bind_addr(lc_socket_t *sock, short port) { const int opt = 1; struct sockaddr_in6 any = { .sin6_family = AF_INET6, .sin6_addr = IN6ADDR_ANY_INIT, .sin6_port = port }; if ((setsockopt(sock->sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt))) == -1) return LC_ERROR_SETSOCKOPT; #ifdef SO_REUSEPORT if ((setsockopt(sock->sock, SOL_SOCKET, SO_REUSEPORT, &opt, sizeof(opt))) == -1) return LC_ERROR_SETSOCKOPT; #endif if (bind(sock->sock, (struct sockaddr *)&any, sizeof(struct sockaddr_in6)) == -1) { /* ignore EINVAL "socket already bound" and EADDRINUSE errors */ if (errno != EINVAL && errno != EADDRINUSE) return LC_ERROR_SOCKET_BIND; } return 0; } int lc_channel_bind(lc_socket_t *sock, lc_channel_t *chan) { int rc = 0; /* Librecast sockets can have multiple channels bound to them, but we * only need to call lc_socket_bind_addr() the first time */ if (sock->type == LC_SOCK_IN6) { lc_channel_in6addr(chan); /* generate group address (IPv6 socket only) */ rc = (sock->bound) ? 0 : lc_socket_bind_addr(sock, chan->sa.sin6_port); } if (!rc) { astor(&chan->sock, sock); sock->bound++; chan->sock->ccoding |= chan->coding; #ifdef HAVE_LIBLCRQ if (chan->T > sock->T) sock->T = chan->T; #endif } return rc; } static lc_channel_t * lc_channel_ins(lc_ctx_t *ctx, lc_channel_t *chan) { chan->next = aload(&ctx->chan_list); chan->readers = 1; CAE_loop(&ctx->chan_list, &chan->next, chan); return chan; } lc_channel_t * lc_channel_sidehash(lc_channel_t *base, unsigned char *key, size_t keylen) { #ifndef HASH_TYPE return (errno = ENOTSUP), NULL; #else lc_ctx_t *ctx = base->ctx; lc_channel_t *side = lc_channel_copy(ctx, base); if (!side) return NULL; hash_generic_key(side->hash, HASHSIZE, base->hash, HASHSIZE, key, keylen); /* force regeneration of IPv6 group address */ memset(&side->sa, 0, sizeof(struct sockaddr_in6)); lc_channel_in6addr(side); return side; #endif } lc_channel_t * lc_channel_sideband(lc_channel_t *base, uint64_t band) { struct in6_addr *in; uint64_t *ptr; lc_ctx_t *ctx = base->ctx; lc_channel_t *side = lc_channel_copy(ctx, base); if (!side) return NULL; in = &side->sa.sin6_addr; ptr = (uint64_t *)&in->s6_addr[8]; *ptr = band; return side; } lc_channel_t * lc_channel_copy(lc_ctx_t *ctx, lc_channel_t *chan) { lc_channel_t *copy = malloc(sizeof(lc_channel_t)); if (!copy) return NULL; memset(copy, 0, sizeof(lc_channel_t)); memcpy(copy->hash, chan->hash, HASHSIZE); copy->ctx = ctx; copy->sa = chan->sa; copy->coding = chan->coding; copy->key = chan->key; copy->pek = chan->pek; copy->sek = chan->sek; copy->ssk = chan->ssk; if (clock_gettime(CLOCK_TAI, &chan->byt_reset)) { free(copy); return NULL; } return lc_channel_ins(ctx, copy); } lc_channel_t * lc_channel_nnew(lc_ctx_t *ctx, unsigned char *s, size_t len) { lc_channel_t *chan; chan = malloc(sizeof(lc_channel_t)); if (!chan) return NULL; memset(chan, 0, sizeof(lc_channel_t)); hash_generic(chan->hash, HASHSIZE, s, len); chan->ctx = ctx; chan->bps_out = ctx->bps_out; chan->bps_in = ctx->bps_in; chan->coding = ctx->coding; chan->key = ctx->key; chan->pek = ctx->pek; chan->sek = ctx->sek; chan->psk = ctx->psk; chan->ssk = ctx->ssk; if (clock_gettime(CLOCK_TAI, &chan->byt_reset)) { free(chan); return NULL; } #ifdef HAVE_LIBLCRQ chan->T = LC_DEFAULT_RQ_T; chan->rq_oh = ctx->rq_oh; #endif return lc_channel_ins(ctx, chan); } lc_channel_t * lc_channel_new(lc_ctx_t *ctx, char *s) { return lc_channel_nnew(ctx, (unsigned char *)s, strlen(s)); } lc_channel_t *lc_channel_init(lc_ctx_t *ctx, struct sockaddr_in6 *sa) { lc_channel_t *chan; chan = lc_channel_nnew(ctx, (unsigned char *)&sa->sin6_addr + 2, 14); if (!chan) return NULL; chan->sa = *sa; return chan; } lc_channel_t *lc_channel_init_grp(lc_ctx_t *ctx, struct in6_addr *grp, short port) { struct sockaddr_in6 sa = { .sin6_family = AF_INET6, .sin6_port = htons(port) }; sa.sin6_addr = *grp; return lc_channel_init(ctx, &sa); } void lc_hashtoaddr(struct in6_addr *addr, unsigned char *hash, size_t hashlen, unsigned char flags) { addr->s6_addr[0] = 0xff; /* multicast */ addr->s6_addr[1] = flags; /* set flags */ memcpy(&addr->s6_addr[2], hash, MIN(hashlen, 14)); /* 112 bits (14 bytes) for hash */ } lc_channel_t * lc_channel_hash(lc_ctx_t *ctx, unsigned char *hash, size_t hashlen, unsigned char flags, short port) { struct sockaddr_in6 sa = { .sin6_family = AF_INET6, .sin6_port = htons(port) }; lc_hashtoaddr(&sa.sin6_addr, hash, hashlen, flags); return lc_channel_init(ctx, &sa); } lc_channel_t *lc_channel_random(lc_ctx_t *ctx) { unsigned char buf[14]; if (lc_getrandom(buf, sizeof buf) != sizeof buf) return NULL; return lc_channel_nnew(ctx, buf, sizeof buf); } #ifndef IPV6_MULTICAST_ALL static int lc_socket_groups_free(lc_socket_t *sock) { lc_grplist_t *tmp; for (lc_grplist_t *g = sock->grps; g; ) { tmp = g; g = g->next; free(tmp); } return 0; } #endif /* remove socket from ctx list */ static void socket_unlink(lc_socket_t *sock) { pthread_mutex_lock(&sock->ctx->mtx); lc_socket_t *prev = NULL; lc_socket_t *next = aload(&sock->next); for (lc_socket_t *p = aload(&sock->ctx->sock_list); p; p = aload(&p->next)) { if (p == sock) { lc_socket_t **ptr = (prev) ? &prev->next : &sock->ctx->sock_list; CAE_loop(ptr, &p, next); break; } prev = p; } pthread_mutex_unlock(&sock->ctx->mtx); } void lc_socket_close(lc_socket_t *sock) { int err = errno; if (!sock) return; #ifndef IPV6_MULTICAST_ALL lc_socket_groups_free(sock); #endif lc_socket_listen_cancel(sock); socket_unlink(sock); int deleted = 0; if (CAE(&sock->deleted, &deleted, DELETE_LATER)) lc_socket_release(sock); errno = err; } inline static void ctx_free(lc_ctx_t *ctx) { int deleted = aload(&ctx->deleted); CAE(&ctx->deleted, &deleted, DELETE_LATER); lc_ctx_release(ctx); } void lc_ctx_free(lc_ctx_t *ctx) { int err = errno; if (ctx) { void *p; if (ctx->q) lc_ctx_qpool_free(ctx); while ((p = aload(&ctx->sock_list))) { lc_socket_close(p); } while ((p = aload(&ctx->chan_list))) { lc_channel_free(p); } while ((p = aload(&ctx->router_list))) { lc_router_free(p); } if (ctx->sock >= 0) close(ctx->sock); if (ctx->mdex) mdex_free(ctx->mdex); pthread_mutex_destroy(&ctx->mtx); ctx_free(ctx); } errno = err; } int lc_socket_bind(lc_socket_t *sock, unsigned int ifx) { if (setsockopt(sock->sock, IPPROTO_IPV6, IPV6_MULTICAST_IF, &ifx, sizeof ifx) == -1) { return -1; } sock->ifx = ifx; return 0; } static lc_socket_t * lc_socket_nnew(lc_ctx_t *ctx, int type) { lc_socket_t *sock; int s = 0, i, err = 0; sock = calloc(1, sizeof(lc_socket_t)); if (!sock) return NULL; sock->ctx = ctx; sock->type = type; sock->readers = 1; sock->ttl = DEFAULT_MULTICAST_HOPS; if (type == LC_SOCK_IN6) { s = socket(AF_INET6, SOCK_DGRAM, 0); if (s == -1) { err = errno; goto err_free_sock; } sock->sock = s; #ifdef IPV6_MULTICAST_ALL /* available in Linux 4.2 onwards */ i = 0; if (setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_ALL, &i, sizeof i) == -1) { goto err_close_s; } #endif i = 1; if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVPKTINFO, &i, sizeof i) == -1) { goto err_close_s; } i = DEFAULT_MULTICAST_LOOP; if (setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &i, sizeof i) == -1) { goto err_close_s; } i = DEFAULT_MULTICAST_HOPS; if (setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &i, sizeof i) == -1) { goto err_close_s; } if (ctx->ifx && lc_socket_bind(sock, ctx->ifx)) goto err_close_s; } sock->next = aload(&ctx->sock_list); CAE_loop(&ctx->sock_list, &sock->next, sock); return sock; err_close_s: err = errno; if (s) close(s); err_free_sock: free(sock); return (errno = err), NULL; } lc_socket_t * lc_socket_new(lc_ctx_t *ctx) { return lc_socket_nnew(ctx, LC_SOCK_IN6); } int lc_socketpair(lc_ctx_t *ctx, lc_socket_t *sock[2]) { int sv[2]; int err; sock[0] = lc_socket_nnew(ctx, LC_SOCK_PAIR); if (!sock[0]) return -1; sock[1] = lc_socket_nnew(ctx, LC_SOCK_PAIR); if (!sock[1]) goto err_sock_close; err = socketpair(AF_UNIX, SOCK_DGRAM, 0, sv); if (err) goto err_sock_close; for (int i = 0; i < 2; i++) { sock[i]->sock = sv[i]; sock[i^0]->pair = sock[i^1]; /* pair our socks */ } return 0; err_sock_close: err = errno; for (int i = 0; i < 2; i++) lc_socket_close(sock[0]); errno = err; return -1; } q_t *lc_ctx_q(lc_ctx_t *ctx) { return ctx->q; } int lc_ctx_qpool_free(lc_ctx_t *ctx) { int err = 0, rc = 0; if (q_pool_destroy(ctx->tid, ctx->nthreads)) err = errno, rc = -1; free(ctx->tid); ctx->tid = NULL; free(ctx->q); ctx->q = NULL; if (err) errno = err; return rc; } int lc_ctx_qpool_resize(lc_ctx_t *ctx, int nthreads) { pthread_t *tid; int rc = 0, newtids; if (nthreads == ctx->nthreads) return 0; if (nthreads < ctx->nthreads) { newtids = ctx->nthreads - nthreads; rc = q_pool_destroy(&ctx->tid[nthreads], newtids); if (rc) return -1; ctx->nthreads = nthreads; } tid = realloc(ctx->tid, sizeof(pthread_t) * nthreads); if (!tid) return -1; ctx->tid = tid; if (nthreads > ctx->nthreads) { newtids = nthreads - ctx->nthreads; memset(&tid[ctx->nthreads], 0, sizeof(pthread_t) * newtids); rc = q_pool_create(&ctx->tid[ctx->nthreads], newtids, &q_job_seek, ctx->q); ctx->nthreads = nthreads - rc; } return (ctx->nthreads == nthreads) ? 0 : -1; } int lc_ctx_qpool_init(lc_ctx_t *ctx, int nthreads) { int err; ctx->q = malloc(sizeof(q_t)); if (!ctx->q) return -1; if (q_init(ctx->q)) { err = errno; goto err_free_ctx_q; } ctx->tid = calloc(nthreads, sizeof(pthread_t)); if (!ctx->tid) { err = errno; goto err_q_free; } ctx->nthreads = nthreads - q_pool_create(ctx->tid, nthreads, &q_job_seek, ctx->q); return (ctx->nthreads == nthreads) ? 0 : -1; err_q_free: q_free(ctx->q); err_free_ctx_q: free(ctx->q); return (errno = err), -1; } void lc_ctx_release(lc_ctx_t *ctx) { /* decrease reference count, fetch updated value */ int refs = add_fetch(&ctx->readers, -1); int deleted = aload(&ctx->deleted); if (!refs && deleted == DELETE_LATER) { /* no readers left, try to delete */ if (CAE(&ctx->deleted, &deleted, DELETE_IN_PROGRESS)) { free(ctx); } } } void lc_socket_release(lc_socket_t *sock) { /* decrease reference count, fetch updated value */ int refs = add_fetch(&sock->readers, -1); int deleted = aload(&sock->deleted); if (!refs && deleted == DELETE_LATER) { /* no readers left, try to delete */ if (CAE(&sock->deleted, &deleted, DELETE_IN_PROGRESS)) { if (sock->sock) close(sock->sock); if (sock->oil) free(sock->oil); free(sock); } } } void lc_channel_release(lc_channel_t *chan) { /* decrease reference count, fetch updated value */ int refs = add_fetch(&chan->readers, -1); int deleted = aload(&chan->deleted); if (!refs && deleted == DELETE_LATER) { /* no readers left, try to delete */ if (CAE(&chan->deleted, &deleted, DELETE_IN_PROGRESS)) { free(chan); } } } lc_ctx_t *lc_ctx_acquire(lc_ctx_t *ctx) { if (!ctx || aload(&ctx->deleted)) return NULL; fetch_add(&ctx->readers, 1); /* increase reference count */ return ctx; } lc_socket_t *lc_socket_acquire(lc_socket_t *sock) { if (!sock || aload(&sock->deleted)) return NULL; fetch_add(&sock->readers, 1); /* increase reference count */ return sock; } lc_channel_t *lc_channel_acquire(lc_channel_t *chan) { if (!chan || aload(&chan->deleted)) return NULL; fetch_add(&chan->readers, 1); /* increase reference count */ return chan; } lc_ctx_t * lc_ctx_new(void) { lc_ctx_t *ctx; if (!(ctx = calloc(1, sizeof(lc_ctx_t)))) return NULL; /* errno set by calloc */ ctx->next = aload(&ctx_list); astor(&ctx_list, ctx); ctx->sock = -1; ctx->readers = 1; #ifdef HAVE_LIBLCRQ ctx->rq_oh = -1; #endif if (pthread_mutex_init(&ctx->mtx, NULL)) { free(ctx); return NULL; } return ctx; } int lc_ctx_debug(lc_ctx_t *ctx, int debug) { if (debug != -1) ctx->debug = debug; return ctx->debug; } FILE *lc_ctx_stream(lc_ctx_t *ctx, FILE *stream) { if (stream) ctx->stream = stream; return ctx->stream; } librecast/src/librecast_pvt.h000066400000000000000000000175601502456746400166550ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2017-2025 Brett Sheffield */ #ifndef _LIBRECAST_PVT_H #define _LIBRECAST_PVT_H 1 #define _LIBRECAST_PRIVATE #include #include #include #include #include #ifdef HAVE_LIBLCRQ # include #endif #ifdef HAVE_MLD # include # include #endif #ifdef HAVE_ENDIAN_H # include #elif defined(HAVE_SYS_ENDIAN_H) # include #elif defined(HAVE_LIBKERN_OSBYTEORDER_H) # include # define htobe64(x) OSSwapHostToBigInt64(x) # define be64toh(x) OSSwapBigToHostInt64(x) #endif /* fall back to CLOCK_REALTIME when Linux-specific CLOCK_TAI is unavailable */ #ifndef CLOCK_TAI # define CLOCK_TAI CLOCK_REALTIME #endif #define NANO 1000000000 enum { DELETE_LATER = 1, /* marked for deletion */ DELETE_IN_PROGRESS = 2, /* deletion in progress */ }; #define aload(x) __atomic_load_n((x), __ATOMIC_ACQUIRE) #define astor(x, y) __atomic_store_n((x),(y), __ATOMIC_RELEASE) #define fetch_add(x, y) __atomic_fetch_add((x),(y), __ATOMIC_ACQ_REL) #define add_fetch(x, y) __atomic_add_fetch((x),(y), __ATOMIC_ACQ_REL) #define CAE(a, b, c) __atomic_compare_exchange_n((a), (b), (c), 0, \ __ATOMIC_RELEASE, __ATOMIC_ACQUIRE) #define CAE_weak(a, b, c) __atomic_compare_exchange_n((a), (b), (c), 1, \ __ATOMIC_RELEASE, __ATOMIC_ACQUIRE) #define CAE_loop(a, b, c) while(!__atomic_compare_exchange_n((a), (b), (c), 1, \ __ATOMIC_RELEASE, __ATOMIC_ACQUIRE)) #define fetch_and_ACQ(x, y) __atomic_fetch_and((x), (y), __ATOMIC_ACQUIRE) #define fetch_and(x, y) __atomic_fetch_and((x), (y), __ATOMIC_ACQ_REL) #define fetch_or_REL(x, y) __atomic_fetch_or((x), (y), __ATOMIC_RELEASE) #define or_fetch(x, y) __atomic_or_fetch((x), (y), __ATOMIC_ACQ_REL) #define fetch_or_REL(x, y) __atomic_fetch_or((x), (y), __ATOMIC_RELEASE) typedef struct lc_ctx_t { lc_ctx_t *next; lc_socket_t *sock_list; lc_channel_t *chan_list; lc_router_t *router_list; mdex_t *mdex; q_t *q; /* context queue */ pthread_t *tid; /* array of nthreads worker threads */ pthread_mutex_t mtx; /* mutex for sock + chan lists */ lc_key_t key; /* symmetric key */ lc_key_t pek; /* public encryption key */ lc_key_t sek; /* secret encryption key */ lc_key_t psk; /* public signing key */ lc_key_t ssk; /* secret signing key */ FILE *stream; int debug; int coding; /* encryption/encoding to use */ int nthreads; /* number of ctx worker threads */ size_t bps_out; /* send rate limit (bps) */ size_t bps_in; /* recv rate limit (bps) */ unsigned int ifx; /* default interface for sockets and channels */ int sock; /* AF_LOCAL socket for ioctls */ int readers; /* reference count (readers) */ int deleted; /* marked for deletion */ #ifdef HAVE_LIBLCRQ int rq_oh; /* RaptorQ automatic overhead pkts. Default: -1 (off) */ #endif } lc_ctx_t; #ifndef IPV6_MULTICAST_ALL typedef struct lc_grplist_s lc_grplist_t; struct lc_grplist_s { lc_grplist_t *next; struct in6_addr grp; }; #endif typedef struct lc_socket_t { lc_socket_t *next; lc_socket_t *pair; /* other socket, if type == LC_SOCK_PAIR */ lc_ctx_t *ctx; lc_channel_t *chan_active; /* channel currently in use */ lc_router_t *router; unsigned char *oil; lc_socktype_t type; pthread_t thread; size_t byt_out; /* bytes sent */ size_t byt_in; /* bytes recv */ unsigned int pkt_out; /* pkts sent */ unsigned int pkt_in; /* pkts recv */ struct timespec byt_reset; /* byte counter reset */ unsigned int ifx; /* interface index, 0 = all (default) */ #ifndef IPV6_MULTICAST_ALL lc_grplist_t *grps; #endif int ttl; /* Time to Live for packets sent from this socket */ int bound; /* how many channels are bound to this socket */ int ccoding; /* combined bits of all channel encodings in use on this socket */ int status; /* router port status */ int sock; int readers; /* reference count (readers) */ int deleted; /* marked for deletion */ uint16_t T; /* RaptorQ symbol size (bytes) */ } lc_socket_t; /* single packet being logged for NACK/replay thread */ typedef struct lc_packet_log_t lc_packet_log_t; struct lc_packet_log_t { lc_packet_log_t * next; size_t len; /* length of original packet on the wire */ time_t time; /* time the packet was logged */ lc_seq_t seq; /* packet's sequence number */ char data[]; /* packet data as sent on the wire */ }; /* information used when logging messages for a NACK/replay thread */ typedef struct lc_channel_logging_t { pthread_t nack_thread; int n_seconds; lc_channel_t * chan_nack; /* channel we receive NACKs on */ lc_socket_t * sock_nack; /* socket we receive NACKs on */ lc_channel_t * chan_data; /* channel we send replay packets on */ pthread_mutex_t mutex; /* lock this before accessing anything below */ lc_packet_log_t * oldest; /* linked list of logged messages */ lc_packet_log_t * newest; /* other end of list pointed to by oldest */ } lc_channel_logging_t; /* information used when detecting gaps in sequence numbers and generating NACKs */ typedef struct lc_channel_gap_detect_t { lc_seq_t next; /* next sequence number expected, 0 if we don't know */ lc_channel_t * chan_nack; /* channel we send NACKs on */ lc_socket_t * sock_nack; /* socket we send NACKs on */ uint64_t bitmap; /* which of the last 64 packets actually arrived; bit n == next + 64 - n */ } lc_channel_gap_detect_t; typedef struct lc_oid_s { unsigned char hash[HASHSIZE]; int status; } lc_oid_t; typedef struct lc_channel_t { lc_channel_t *next; lc_ctx_t *ctx; struct lc_socket_t *sock; struct sockaddr_in6 sa; unsigned char hash[HASHSIZE]; /* full channel hash */ size_t byt_out; /* bytes sent */ size_t byt_in; /* bytes recv */ size_t bps_out; /* send rate limit (bps) */ size_t bps_in; /* recv rate limit (bps) */ struct timespec byt_reset; /* byte counter reset */ lc_seq_t seq; /* sequence number (Lamport clock) */ lc_rnd_t rnd; /* random nonce */ lc_key_t key; /* symmetric key */ lc_key_t pek; /* public encryption key */ lc_key_t sek; /* secret encryption key */ lc_key_t psk; /* public signing key */ lc_key_t ssk; /* secret signing key */ lc_filter_t *filter; /* channel filter */ lc_token_t *token; /* channel token (sending) */ int coding; /* encryption/encoding to use */ #ifdef HAVE_LIBLCRQ rq_pid_t pid; rq_t *rq; /* RaptorQ context */ uint32_t *ESI; /* RaptorQ Encoding Symbol IDs (ESI): 24-bit unsigned integer */ uint8_t *rq_blk; /* RaptorQ blocks */ uint16_t T; /* RaptorQ symbol size (bytes) */ uint16_t orig; /* original symbols received */ uint16_t syms; /* symbols received */ lc_oid_t oid[2]; /* Object ID */ int oid_cur; /* idx of most recent oid */ int rq_oh; /* RaptorQ automatic overhead pkts. Default: -1 (off) */ #endif lc_channel_logging_t *logging; lc_channel_gap_detect_t *gap_detect; int readers; /* reference count (readers) */ int deleted; /* marked for deletion */ } lc_channel_t; typedef struct lc_message_head_t { uint64_t timestamp; /* nanosecond timestamp */ lc_seq_t seq; /* sequence number */ lc_rnd_t rnd; /* nonce */ uint8_t op; lc_len_t len; } __attribute__((__packed__)) lc_message_head_t; struct lc_sync_options_s { char *share; size_t sharelen; size_t trim; }; #ifdef HAVE_MLD #include #include struct qentry_s { struct in6_addr grp; mdex_entry_t entry; }; struct lc_share_s { lc_ctx_t *lctx; lc_stat_t *stats; mdex_t *mdex; mld_t *mld; mld_watch_t *watch; pthread_t *tsend; q_t q; int nthread_send; unsigned int ifx; int flags; int readers; /* reference count (readers) */ int deleted; /* marked for deletion */ }; #endif extern uint32_t ctx_id; extern uint32_t sock_id; extern uint32_t chan_id; extern lc_ctx_t *ctx_list; extern lc_socket_t *sock_list; extern lc_channel_t *chan_list; #define BUFSIZE 1500 #define DEFAULT_FLAGS 0x1e #define SIDE_CHANNEL_NACK "NACK" #endif /* _LIBRECAST_PVT_H */ librecast/src/mdex.c000066400000000000000000000523661502456746400147470ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2023 Brett Sheffield */ #include #include #include #include #include #include #include #include #include #include static int mdex_addfile_root(mdex_t *mdex, const char *path, q_t *q, int flags, unsigned char *root); char *mdex_sharepath(mdex_t *mdex, const char *restrict path) { char *base, *rpath, *sharepath; size_t blen; int err = 0; rpath = canonpath(path); if (!rpath) return NULL; base = strdup(mdex->basedir); if (!base) goto err_free_rpath; blen = mdex->basedirlen - strlen(basename(base)); free(base); sharepath = strdup(rpath + blen); if (!sharepath) goto err_free_rpath; free(rpath); return sharepath; err_free_rpath: err = errno; free(rpath); errno = err; return NULL; } static void * mdex_stack_pop(mdex_stack_t *stack) { return (stack->ptr) ? stack->stack[--(stack->ptr)] : NULL; } static int mdex_stack_push(mdex_stack_t *stack, void *ptr) { if (!stack->ptr || stack->ptr >= MDEX_STACK_SZ) { stack->len += MDEX_STACK_SZ; stack->stack = realloc(stack->stack, stack->len * sizeof(void *)); if (!stack->stack) return -1; } stack->stack[(stack->ptr)++] = ptr; return 0; } int mdex_get(mdex_t *mdex, unsigned char *hash, size_t hashlen, mdex_entry_t *entry) { mdex_idx_t *idx; int rc; if (!mdex || !hash || !hashlen) return (errno = EINVAL), -1; idx = mdex->root; if (!idx) return (errno = ENOENT), -1; while ((rc = memcmp(idx->hash, hash, hashlen))) { idx = (rc < 0) ? idx->clown : idx->joker; if (!idx) return (errno = ENOENT), -1; } if (entry && idx->entry) { if (idx->entry->type == MDEX_ALIAS) { if (!memcmp(hash, idx->entry->ptr.data, hashlen)) return (errno = ELOOP), -1; memcpy(hash, idx->entry->ptr.data, hashlen); return mdex_get(mdex, hash, hashlen, entry); } *entry = *idx->entry; } return 0; } void mdex_aliashash(const char *path, unsigned char *hash, size_t hashlen) { hash_generic(hash, hashlen, (unsigned char *)path, strlen(path)); } int mdex_getalias(mdex_t *mdex, const char *path, mdex_entry_t *entry) { unsigned char hash[HASHSIZE]; char *sharepath = mdex_sharepath(mdex, path); if (!sharepath) return -1; mdex_aliashash(sharepath, hash, sizeof hash); free(sharepath); return mdex_get(mdex, hash, sizeof hash, entry); } static int mdex_alloc(mdex_t *mdex) { size_t pages; void *ptr; int err; if (!mdex->pagesz) return (errno = EINVAL), -1; if (!mdex->entries) mdex->entries++; pages = howmany(mdex->entries * sizeof(mdex_idx_t), mdex->pagesz); if (!pages) return (errno = EINVAL), -1; ptr = calloc(pages, mdex->pagesz); if (!ptr || mdex_stack_push(&mdex->alloc_stack, ptr)) goto exit_cleanup; if (!mdex->head) { mdex->head = ptr; mdex->root = mdex->head; } mdex->next = ptr; mdex->last = (mdex_idx_t *)((char *)ptr + mdex->entries * sizeof(mdex_idx_t)); pages = howmany(mdex->entries * sizeof(mdex_entry_t), mdex->pagesz); ptr = calloc(pages, mdex->pagesz); if (!ptr || mdex_stack_push(&mdex->alloc_stack, ptr)) goto exit_cleanup; if (!mdex->head_entry) { mdex->head_entry = ptr; mdex->next_entry = mdex->head_entry; } mdex->next_entry = ptr; return 0; exit_cleanup: err = errno; free(ptr); errno = err; return -1; } int mdex_put(mdex_t *mdex, unsigned char *hash, size_t hashlen, mdex_entry_t *entry) { mdex_idx_t *new, *idx, **ptr; int rc; if (!mdex || !hash || !hashlen) return (errno = EINVAL), -1; new = mdex_stack_pop(&mdex->idx_stack); if (!new) { if (!mdex->next) { if (mdex_alloc(mdex) == -1) return -1; } new = mdex->next++; if (mdex->next >= mdex->last) mdex->next = NULL; /* force allocation */ } idx = mdex->root; memcpy(new->hash, hash, hashlen); while ((rc = memcmp(idx->hash, hash, hashlen))) { ptr = (rc < 0) ? &idx->clown : &idx->joker; if (!*ptr) { *ptr = new; break; } idx = *ptr; } if (entry) { if (!rc && idx) new = idx; /* overwrite existing entry */ new->entry = mdex_stack_pop(&mdex->entry_stack); if (!new->entry) new->entry = mdex->next_entry++; *new->entry = *entry; if ((new->entry->type & MDEX_FILE) && new->entry->file.file.name) { /* increment reference count for filename */ new->entry->file.file.ref++; } entry->idx = idx; } return 0; } int mdex_alias(mdex_t *mdex, unsigned char *alias, size_t aliaslen, unsigned char *hash, size_t hashlen) { mdex_entry_t entry = { .type = MDEX_ALIAS }; mdex_idx_t *idx; int rc; if (!mdex || !hash || !hashlen || !alias || !aliaslen) return (errno = EINVAL), -1; idx = mdex->root; if (!idx) return (errno = ENOENT), -1; while ((rc = memcmp(idx->hash, hash, hashlen))) { idx = (rc < 0) ? idx->clown : idx->joker; if (!idx) return (errno = ENOENT), -1; } entry.ptr.size = hashlen; entry.ptr.data = idx->hash; return mdex_put(mdex, alias, aliaslen, &entry); } int mdex_alias_hash(mdex_t *mdex, const char *path, unsigned char *hash, size_t hashlen) { unsigned char alias[HASHSIZE]; char *sharepath = mdex_sharepath(mdex, path); if (!sharepath) return -1; hash_generic(alias, sizeof alias, (unsigned char *)sharepath, strlen(sharepath)); free(sharepath); return mdex_alias(mdex, alias, sizeof alias, hash, hashlen); } /* build the entries hash from the path, attributes and subdirectory entries */ void mdex_hash_entry(unsigned char *hash, size_t hashlen, const char *path, struct stat *sb, mdex_hash_t *dir, int entries) { hash_state state; memset(hash, 0, hashlen); hash_init(&state, NULL, 0, hashlen); if (path) { char *tmp = strdup(path); char *base = basename(tmp); hash_update(&state, (unsigned char *)base, strlen(base)); free(tmp); } if (sb) { hash_update(&state, (unsigned char *)&sb->st_mode, sizeof(uint16_t)); hash_update(&state, (unsigned char *)&sb->st_uid, sizeof(uid_t)); hash_update(&state, (unsigned char *)&sb->st_gid, sizeof(gid_t)); hash_update(&state, (unsigned char *)&sb->st_mtim.tv_sec, sizeof(uint64_t)); long nsec = sb->st_mtim.tv_nsec >> 3 << 3; /* reduce precision */ hash_update(&state, (unsigned char *)&nsec, sizeof(long)); } for (int i = 0; i < entries; i++) hash_update(&state, dir[i], hashlen); hash_final(&state, hash, hashlen); } void mdex_tree_hash_sb(unsigned char *hash, size_t hashlen, mtree_t *mtree, size_t n, struct stat *sb, const char *path) { hash_state state; memset(hash, 0, hashlen); hash_init(&state, NULL, 0, hashlen); if (path) { /* remove first segment of sharepath (the "sharename") before * including in hash (path has already been canonicalised) */ const char *relsharepath = strchr(path, '/'); if (!relsharepath) relsharepath = path; hash_update(&state, (unsigned char *)relsharepath, strlen(relsharepath)); } if (mtree && mtree->len) { /* root hash + key */ hash_update(&state, mtree_nnode(mtree, 0), hashlen); hash_update(&state, (unsigned char *)&n, sizeof(n)); } if (sb) { hash_update(&state, (unsigned char *)&sb->st_mode, sizeof(uint16_t)); hash_update(&state, (unsigned char *)&sb->st_uid, sizeof(uid_t)); hash_update(&state, (unsigned char *)&sb->st_gid, sizeof(gid_t)); hash_update(&state, (unsigned char *)&sb->st_mtim.tv_sec, sizeof(uint64_t)); long nsec = sb->st_mtim.tv_nsec >> 3 << 3; /* reduce precision */ hash_update(&state, (unsigned char *)&nsec, sizeof(long)); } hash_final(&state, hash, hashlen); } int mdex_tree_hash(unsigned char *hash, size_t hashlen, mtree_t *mtree, size_t n) { return hash_generic_key(hash, hashlen, mtree_nnode(mtree, 0), HASHSIZE, (unsigned char *)&n, sizeof(n)); } static int mdex_tree(mdex_t *mdex, mtree_t *mtree, const char *path, struct stat *sb) { net_tree_t *data; unsigned char hash[HASHSIZE]; char *sharepath = NULL; mdex_entry_t entry = {0}; size_t hashsz = 0, off = 0, len, namesz = 0; int rc = -1; entry.type = MDEX_PTR | MDEX_OTI; if (mtree && mtree->len) { entry.ptr.size = HASHSIZE * mtree->nodes; hashsz = mtree->nodes * HASHSIZE; } if (path) { sharepath = mdex_sharepath(mdex, path); if (!sharepath) return -1; namesz = strlen(sharepath); if (namesz > UINT16_MAX) { free(sharepath); return (errno = ENAMETOOLONG), -1; } } len = sizeof (net_tree_t) + hashsz + namesz; data = malloc(len); if (!data || mdex_stack_push(&mdex->alloc_stack, data)) { free(data); free(sharepath); return -1; } memset(data, 0, len); if (mtree && mtree->len) { data->size = htobe64(mtree->len); memcpy(data->tree + namesz, mtree->tree, hashsz); } if (namesz) { data->namesz = htons(namesz); memcpy(data->tree, sharepath, namesz); } if (sb) { data->atime_s = sb->st_atim.tv_sec; data->atime_n = sb->st_atim.tv_nsec; data->mtime_s = sb->st_mtim.tv_sec; data->mtime_n = sb->st_mtim.tv_nsec; data->mode = sb->st_mode; data->uid = sb->st_uid; data->gid = sb->st_gid; } if (hashsz) memcpy(data->tree + namesz, mtree->tree, hashsz); size_t parts = howmany(len, MTREE_CHUNKSIZE); for (size_t z = 0; z < parts; z++) { mdex_tree_hash_sb(hash, HASHSIZE, mtree, z, sb, sharepath); entry.ptr.size = MIN(MTREE_CHUNKSIZE, len); entry.ptr.data = (char *)data + off; rc = mdex_put(mdex, hash, HASHSIZE, &entry); if (rc == -1) break; len -= MTREE_CHUNKSIZE, off += MTREE_CHUNKSIZE; } if (namesz) free(sharepath); return rc; } int mdex_add(mdex_t *mdex, void *data, size_t len, q_t *q, int flags) { (void) flags; /* unused */ mtree_t *mtree; unsigned char *hash; mdex_entry_t entry = {0}; size_t min, max, off = 0; int err; mtree = malloc(sizeof (mtree_t)); if (!mtree) return -1; if (mtree_init(mtree, len) == -1) goto exit_cleanup; if (mtree_build(mtree, data, q) == -1) goto exit_cleanup; /* index mtree */ if (mdex_tree(mdex, mtree, NULL, NULL) == -1) goto exit_cleanup; /* write entries for each chunk */ entry.type = MDEX_PTR; min = mtree_subtree_data_min(mtree->base, 0); max = min + mtree->chunks - 1; for (size_t z = min; z <= max; z++) { hash = mtree_nnode(mtree, z); entry.ptr.size = MIN(MTREE_CHUNKSIZE, len); entry.ptr.data = (char *)data + off; mdex_put(mdex, hash, HASHSIZE, &entry); len -= MTREE_CHUNKSIZE; off += MTREE_CHUNKSIZE; } mtree_free(mtree); free(mtree); return 0; exit_cleanup: err = errno; mtree_free(mtree); free(mtree); errno = err; return -1; } static int mdex_createdir(mdex_t *mdex, const char *path, int flags, mdex_hash_t dir[], int entries, struct stat *sb, mdex_hash_t hash, int depth) { mdex_entry_t entry = {0}; int err = 0; /* do not include path in hash at top level */ const char *hashpath = (depth) ? path : NULL; struct stat *ssb = (depth) ? sb: NULL; /* store path */ entry.file.file.name = mdex_sharepath(mdex, path); if (!entry.file.file.name) return -1; if (mdex_stack_push(&mdex->alloc_stack, entry.file.file.name)) { goto err_free_path; } /* copy stat buffer */ entry.file.file.sb = malloc(sizeof(struct stat)); if (mdex_stack_push(&mdex->alloc_stack, entry.file.file.sb)) { err = errno; free(entry.file.file.sb); goto err_free_stack_path; } *entry.file.file.sb = *sb; entry.type = MDEX_DIR | MDEX_OTI | (flags & MDEX_RAND); entry.file.off = 0; entry.file.size = entries; entry.file.file.dir = dir; mdex_hash_entry(hash, sizeof(mdex_hash_t), hashpath, ssb, dir, entries); /* write directory entry */ if (mdex_put(mdex, hash, HASHSIZE, &entry)) { perror("mdex_put"); } /* write alias of directory name */ if (mdex_alias_hash(mdex, path, hash, HASHSIZE)) { perror("mdex_alias"); } return 0; err_free_stack_path: free(mdex_stack_pop(&mdex->alloc_stack)); errno = err; return -1; err_free_path: err = errno; free(entry.file.file.name); errno = err; return -1; } static int scandirfilter(const struct dirent *dir) { /* filter current and parent directories */ return !(!strcmp(dir->d_name, ".") || !strcmp(dir->d_name, "..")); } /* alphasort_c - locale-independent sort * alphasort(3) uses strcoll(3) which is affected by locale * we need to be sure we get the same order regardless of locale */ static int alphasort_c(const struct dirent **a, const struct dirent **b) { return strcmp((*a)->d_name, (*b)->d_name); } static int mdex_directory(mdex_t *mdex, const char *path, q_t *q, int flags, struct stat *sb, int depth, unsigned char *root) { char dname[PATH_MAX]; // FIXME PATH_MAX mdex_hash_t *dir = NULL; struct dirent **namelist; int e, err = 0, n = 0; if (mdex->debug & MDEX_DEBUG_FILE) { char *sharepath = mdex_sharepath(mdex, path); if (sharepath) { fprintf(mdex->stream, "%s\n", sharepath); free(sharepath); } } e = scandir(path, &namelist, scandirfilter, alphasort_c); if (e == -1) return -1; else if (!e) goto empty_directory; dir = calloc(e, sizeof *dir); /* allocate memory for directory object */ /* for any errors we set err but continue loop to free namelist entries */ if (!dir) err = errno; else if (mdex_stack_push(&mdex->alloc_stack, dir)) err = errno; while (e--) { if (!err && snprintf(dname, sizeof dname, "%s/%s", path, namelist[e]->d_name) > 0) { struct stat lsb; if (lstat(dname, &lsb) == 0) { switch (namelist[e]->d_type) { case DT_DIR: /* without MDEX_RECURSE set, we still * recurse into mdex_directory() once to * write the top level directories */ if (mdex->maxdepth != -1 && depth >= mdex->maxdepth) break; if (mdex_directory(mdex, dname, q, flags, &lsb, depth+1, dir[n++])) { err = errno; break; } break; case DT_LNK: case DT_REG: if (depth && !(flags & MDEX_RECURSE)) break; if (mdex_addfile_root(mdex, dname, q, MDEX_ALIAS, dir[n++]) == -1) { err = errno; break; } break; /* case DT_CHR: */ /* case DT_BLK: */ /* case DT_SOCK: */ /* case DT_FIFO: */ /* case DT_WHT: */ /* case DT_UNKNOWN: */ default: break; } } } free(namelist[e]); } free(namelist); if (err) return (errno = err), -1; empty_directory: return mdex_createdir(mdex, path, flags, dir, n, sb, root, depth); } static int mdex_symlink(mdex_t *mdex, const char *sharepath, const char *path, struct stat *sb, int flags, unsigned char *hash) { mdex_entry_t entry = {0}; int rc = -1, err = 0; /* store path */ entry.file.file.name = strdup(sharepath); if (!entry.file.file.name) return -1; if (mdex_stack_push(&mdex->alloc_stack, entry.file.file.name)) { err = errno; goto err_free_path; } /* copy stat buffer */ entry.file.file.sb = malloc(sizeof(struct stat)); if (mdex_stack_push(&mdex->alloc_stack, entry.file.file.sb)) { err = errno; goto err_free_sb; } *entry.file.file.sb = *sb; entry.type = MDEX_LINK | MDEX_OTI | (flags & MDEX_RAND); mdex_tree_hash_sb(hash, HASHSIZE, NULL, 0, sb, sharepath); /* write symlink entry */ if (mdex_put(mdex, hash, HASHSIZE, &entry)) { err = errno; goto err_free_stack_path; } /* write alias of symlink name */ return mdex_alias_hash(mdex, path, hash, HASHSIZE); err_free_sb: free(entry.file.file.sb); err_free_stack_path: free(mdex_stack_pop(&mdex->alloc_stack)); err_free_path: free(entry.file.file.name); if (err) errno = err; return rc; } /* map file, create mtree and add to mdex, returning copy of root hash if root != NULL */ static int mdex_addfile_root(mdex_t *mdex, const char *path, q_t *q, int flags, unsigned char *root) { struct stat sb = {0}; char *data = NULL, *rpath, *sharepath; mtree_t *mtree = NULL; unsigned char *hash; mdex_entry_t entry = {0}; size_t len, min, max, sz = 0; int err; rpath = canonpath(path); if (!rpath) return -1; sharepath = mdex_sharepath(mdex, rpath); if (!sharepath) goto exit_cleanup; data = lc_mmapfile(rpath, &sz, PROT_READ, MAP_PRIVATE, 0, &sb); mdex->files++; if (data == MAP_FAILED) { switch (errno) { case ENODATA: goto store_path; case EMLINK: err = mdex_symlink(mdex, sharepath, path, &sb, flags, root); break; case EISDIR: if (!(flags & MDEX_RECURSE)) mdex->maxdepth = 1; err = mdex_directory(mdex, rpath, q, flags, &sb, 0, root); break; default: goto exit_cleanup; } free(sharepath); free(rpath); return err; } free(rpath); rpath = NULL; mtree = malloc(sizeof (mtree_t)); if (!mtree) goto exit_cleanup; if (mtree_init(mtree, sz) == -1) goto exit_cleanup; if (mtree_build(mtree, data, q) == -1) goto exit_cleanup; store_path: /* index mtree */ if (mdex_tree(mdex, mtree, path, &sb) == -1) goto exit_cleanup; /* store path */ if (mdex->debug & MDEX_DEBUG_FILE) fprintf(mdex->stream, "%s\n", sharepath); entry.file.file.name = sharepath; if (!entry.file.file.name) goto exit_cleanup; if (mdex_stack_push(&mdex->alloc_stack, entry.file.file.name)) goto exit_cleanup; /* copy stat buffer */ entry.file.file.sb = malloc(sizeof sb); if (!entry.file.file.sb) goto exit_cleanup; if (mdex_stack_push(&mdex->alloc_stack, entry.file.file.sb)) goto exit_cleanup; *entry.file.file.sb = sb; /* write alias for root (hash filename) */ if (flags & MDEX_ALIAS) { mdex_tree_hash_sb(root, HASHSIZE, mtree, 0, &sb, sharepath); if (mdex_alias_hash(mdex, path, root, HASHSIZE) == -1) goto exit_cleanup; if (!mtree) return 0; /* empty file */ } /* write entries for each chunk */ entry.type = MDEX_FILE | (flags & MDEX_RAND); entry.file.off = 0; len = mtree->len; min = mtree_subtree_data_min(mtree->base, 0); max = min + mtree->chunks - 1; for (size_t z = min; z <= max; z++) { hash = mtree_nnode(mtree, z); entry.file.size = MIN(MTREE_CHUNKSIZE, len); mdex_put(mdex, hash, HASHSIZE, &entry); len -= MTREE_CHUNKSIZE; entry.file.off += MTREE_CHUNKSIZE; } mtree_free(mtree); free(mtree); munmap(data, sz); return 0; exit_cleanup: err = errno; if (mtree) { mtree_free(mtree); free(mtree); } if (data) munmap(data, sz); free(sharepath); free(rpath); errno = err; return -1; } static int mdex_basedir(mdex_t *mdex, const char *basedir) { mdex->basedir = canonpath(basedir); if (!mdex->basedir) return -1; mdex->basedirlen = strlen(mdex->basedir); char *tmp = strdup(mdex->basedir); if (!tmp) goto err_free_basedir; mdex->rootdir = strdup(dirname(tmp)); if (!mdex->rootdir) goto err_free_tmp; mdex->rootdirlen = strlen(mdex->rootdir); free(tmp); return 0; err_free_tmp: free(tmp); err_free_basedir: free(mdex->basedir); return -1; } int mdex_addfile(mdex_t *mdex, const char *path, q_t *q, int flags) { unsigned char root[HASHSIZE] = ""; if (mdex_basedir(mdex, path) == -1) return -1; return mdex_addfile_root(mdex, path, q, flags, root); } /* convenience API function to return the root hash of a directory from the * supplied mdex */ int mdex_directory_root(mdex_t *mdex, const char *dir, unsigned char *root) { mdex_entry_t entry = {0}; if (mdex_getalias(mdex, dir, &entry)) return -1; assert(entry.idx); memcpy(root, entry.idx->hash, HASHSIZE); return 0; } /* calculate the directory root hash */ int mdex_get_directory_root(const char *dir, unsigned char *root) { mdex_t *mdex; int rc = -1; mdex = mdex_init(0); if (!mdex) return -1; if (mdex_basedir(mdex, dir) == -1) goto err_free_mdex; rc = mdex_addfile_root(mdex, dir, NULL, MDEX_RECURSE, root); err_free_mdex: mdex_free(mdex); return rc; } int mdex_del(mdex_t *mdex, unsigned char *hash, size_t hashlen) { mdex_idx_t *idx; mdex_idx_t **ptr = NULL; int rc; if (!mdex || !hash || !hashlen) return (errno = EINVAL), -1; idx = mdex->root; while ((rc = memcmp(idx->hash, hash, hashlen))) { ptr = (rc < 0) ? &idx->clown : &idx->joker; if (!*ptr) return (errno = ENOENT), -1; idx = *ptr; } if ((idx->entry->type & MDEX_FILE) && idx->entry->file.file.name) { /* decrement reference count for filename */ if (--idx->entry->file.file.ref == 0) { free(idx->entry->file.file.name); } mdex->files--; } /* push deleted idx + entry onto the stack */ if (mdex_stack_push(&mdex->idx_stack, idx)) return -1; if (mdex_stack_push(&mdex->entry_stack, idx->entry)) return -1; if ((!idx->clown) && (!idx->joker)) { *ptr = NULL; /* no children, just remove */ } else if (idx->clown && !idx->joker) { *ptr = idx->clown; /* hoist left child */ } else if (!idx->clown && idx->joker) { *ptr = idx->joker; /* hoist right child */ } else { /* two children */ /* find successor (smallest node in right subtree) */ mdex_idx_t *s; for (s = idx->joker, ptr = &idx->joker; s && s->clown; ptr = &s->clown, s = s->clown); memcpy(idx->hash, s->hash, hashlen); idx->entry = s->entry; *ptr = s->joker; /* delete successor from tree */ } return 0; } mdex_t *mdex_init(size_t entries) { mdex_t *mdex = calloc(1, sizeof (mdex_t)); mdex->readers = 1; if (mdex) { mdex->pagesz = (size_t)sysconf(_SC_PAGESIZE); /* cannot be < 1 */ mdex->entries = entries; if (entries) mdex_alloc(mdex); mdex->maxdepth = MDEX_DEFAULT_DEPTH; } return mdex; } mdex_t *mdex_acquire(mdex_t *mdex) { if (!mdex || aload(&mdex->deleted)) return NULL; fetch_add(&mdex->readers, 1); /* increase reference count */ return mdex; } void mdex_free_all(mdex_t *mdex) { void *ptr; while ((ptr = mdex_stack_pop(&mdex->alloc_stack))) free(ptr); free(mdex->alloc_stack.stack); free(mdex->entry_stack.stack); free(mdex->idx_stack.stack); free(mdex->basedir); free(mdex->rootdir); free(mdex); } void mdex_release(mdex_t *mdex) { /* decrease reference count, fetch updated value */ int refs = add_fetch(&mdex->readers, -1); int deleted = aload(&mdex->deleted); if (!refs && deleted == DELETE_LATER) { /* no readers left, try to delete */ if (CAE(&mdex->deleted, &mdex, DELETE_IN_PROGRESS)) { mdex_free_all(mdex); } } } void mdex_free(mdex_t *mdex) { mdex_release(mdex); } librecast/src/mtree.c000066400000000000000000000220011502456746400151050ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2020-2024 Brett Sheffield */ #include #include #include #include #include #include #include #include #include #include struct mtree_job_s { mtree_t *tree; sem_t *node; /* semaphores for parent nodes above subtree root level */ size_t root; /* root node of subtree */ int subtrees; /* tree is divided into how many subtrees */ }; /* next_pow2 - Public Domain, credit to Sean Anderson from * https://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2 */ static uint32_t next_pow2(uint32_t v) { v--; v |= v >> 1; v |= v >> 2; v |= v >> 4; v |= v >> 8; v |= v >> 16; return ++v; } void mtree_hexdump(mtree_t *tree, FILE *fd) { char hex[HEXLEN]; for (size_t i = 0; i < tree->nodes; i++) { sodium_bin2hex(hex, HEXLEN, tree->tree + i * HASHSIZE, HASHSIZE); fprintf(fd, "%08zu: %.*s\n", i, HEXLEN, hex); } } void mtree_printmap(unsigned char *map, size_t len, FILE *fd) { for (size_t i = 0; i < len; i++) { fprintf(fd, "%d", !!isset(map, i)); } fputc('\n', fd); } size_t mtree_child(mtree_t *tree, size_t node) { node = (node + 1) * 2 - 1; return (node >= tree->nodes) ? 0 : node; } uint8_t *mtree_nnode(mtree_t *t, size_t node) { if (node >= t->nodes) return (errno = ERANGE), NULL; return t->tree + node * MTREE_HASHSIZE; } static size_t mtree_base(mtree_t *tree) { return next_pow2(tree->chunks); } /* return number of levels for tree with base number of data nodes */ static size_t mtree_levels(size_t base) { return (size_t)log2(next_pow2((uint64_t)base)) + 1; } static size_t mtree_node_level(size_t node) { return (size_t)log2(node + 1); } /* node numbered from 0=root, levels numbered from 0=base */ static size_t mtree_node_level_base(size_t base, size_t node) { size_t rootlvl = mtree_node_level(node); size_t treelvl = mtree_levels(base); assert(treelvl >= rootlvl); return treelvl - rootlvl - 1; } /* return number of nodes in tree with base number of data nodes */ static size_t mtree_size(size_t base) { return (size_t)(next_pow2((uint32_t)base) << 1) - 1; } static size_t mtree_child_base(size_t base, size_t node) { node = (node + 1) * 2 - 1; return (node >= mtree_size(base)) ? 0 : node; } size_t mtree_subtree_data_max(size_t base, size_t root) { size_t n = root; while (mtree_node_level_base(base, n)) { n = mtree_child_base(base, n) + 1; } return n; } size_t mtree_subtree_data_min(size_t base, size_t root) { size_t n = root; while (mtree_node_level_base(base, n)) { n = mtree_child_base(base, n); } return n; } static size_t mtree_blocks_subtree(mtree_t *tree, size_t root) { size_t base = mtree_base(tree); size_t max = mtree_subtree_data_max(base, root); size_t min = mtree_subtree_data_min(base, root); size_t tmin = mtree_subtree_data_min(base, 0); max = MIN(max, tmin + tree->chunks - 1); return max - min + 1; } static size_t mtree_node_offset(size_t node) { size_t npow = 1; size_t lvl = mtree_node_level(node); while (lvl--) npow *= 2; return node - npow + 1; } /* NB: we have no bounds checking or errors, * root MUST NOT be greater than node */ static size_t mtree_node_offset_subtree(size_t node, size_t root) { size_t off = mtree_node_offset(node); size_t a = mtree_node_level(node); size_t b = mtree_node_level(root); size_t d = (1U << a) / (1U << b); while (off > (d - 1)) off -= d; return off; } static size_t mtree_chunkn_len(mtree_t *tree, size_t n) { size_t mod; size_t min = mtree_subtree_data_min(mtree_base(tree), 0); size_t max = mtree_subtree_data_max(mtree_base(tree), 0); max = MIN(max, min + tree->chunks - 1); if (n < min || n > max || n > min + tree->chunks) return 0; mod = tree->len % MTREE_CHUNKSIZE; return ((mod) && (n == max)) ? mod : MTREE_CHUNKSIZE; } /* set map bits for leaf node */ static unsigned char *leafnode(unsigned char *map, mtree_t *t1, size_t root, size_t node, unsigned bits, int set_node) { size_t blen = mtree_chunkn_len(t1, node); unsigned bitcount = howmany(blen, MTREE_CHUNKSIZE / bits); if (set_node) node = mtree_node_offset_subtree(node, root); for (unsigned i = 0; i < bitcount; i++) { setbit(map, node * bits + i); } return map; } static unsigned char *mtree_search_subtree(unsigned char *map, mtree_t *t1, mtree_t *t2, size_t root, size_t node, size_t child, unsigned bits) { size_t *q; /* FIFO queue */ int i = 0, o = 0; /* in / out */ q = calloc(t1->nodes, sizeof(size_t)); if (!q) return NULL; q[i++] = child; child++; q[i++] = child; while ((node = q[o++])) { if (memcmp(mtree_nnode(t1, node), mtree_nnode(t2, node), HASHSIZE)) { child = mtree_child(t1, node); if (child) { q[i++] = child; child++; q[i++] = child; } else leafnode(map, t1, root, node, bits, 1); } } free(q); return map; } /* perform bredth-first search of subtree, return bitmap * bits = number of bits to use per chunk. This is useful if chunksize > MTU, a chunk will be * fragmented into multiple packets * map must be free()d by caller */ unsigned char *mtree_diff_subtree(mtree_t *t1, mtree_t *t2, size_t root, unsigned bits) { unsigned char *map = NULL; size_t base, child, node; if (!memcmp(mtree_nnode(t1, root), mtree_nnode(t2, root), HASHSIZE)) return NULL; /* subtree root matches, stop now */ base = mtree_blocks_subtree(t1, root); if (!base) return NULL; /* zero blocks */ node = (base + (CHAR_BIT - 1)) / CHAR_BIT; map = calloc(bits, base); if (!map) return NULL; child = mtree_child(t1, root); if (!child) { node = mtree_node_offset_subtree(node, root); return leafnode(map, t1, root, node, bits, 0); } return mtree_search_subtree(map, t1, t2, root, node, child, bits); } unsigned char *mtree_diff_map(mtree_t *t1, mtree_t *t2) { return mtree_diff_subtree(t1, t2, 0, 1); } int mtree_verify(mtree_t *t) { unsigned char hash[HASHSIZE]; if (!t) return -1; if (!t->len) return 0; if (t->tree == NULL) return -1; for (size_t node = 1; node < t->nodes - 1; node += 2) { hash_generic(hash, HASHSIZE, mtree_nnode(t, node), MTREE_HASHSIZE * 2); if (memcmp(hash, mtree_nnode(t, mtree_parent(node)), HASHSIZE)) return (errno = EBADMSG), -1; } return 0; } static void mtree_hashparents(struct mtree_job_s *job, size_t node, size_t root) { size_t left = node - 1; size_t parent = mtree_parent(node); uint8_t *hash = job->tree->tree + parent * MTREE_HASHSIZE; unsigned char *in = job->tree->tree + left * MTREE_HASHSIZE; if (left < root) sem_wait(&job->node[left]); hash_generic(hash, HASHSIZE, in, MTREE_HASHSIZE * 2); if (parent <= root) sem_post(&job->node[parent]); if (parent && !(parent & 1)) mtree_hashparents(job, parent, root); } static void * mtree_buildsubtree(void *arg) { struct mtree_job_s *job = (struct mtree_job_s *)arg; /* atomically find root for our subtree */ size_t root = fetch_add(&job->root, 1); size_t noff = mtree_node_offset(root); size_t min = noff * job->tree->base / job->subtrees; size_t max = min + job->tree->base / job->subtrees - 1; for (size_t chunk = min; chunk <= max; chunk++) { /* node => chunk number (base node), starting from 0 */ size_t node = chunk + job->tree->nodes - job->tree->base; if (chunk < job->tree->chunks) { size_t off = chunk * MTREE_CHUNKSIZE; size_t len = MIN(MTREE_CHUNKSIZE, job->tree->len - off); uint8_t *hash = job->tree->tree + node * MTREE_HASHSIZE; unsigned char *in = (unsigned char *)job->tree->data + off; hash_generic(hash, HASHSIZE, in, len); } if (node <= root) sem_post(&job->node[node]); if (chunk & 1) mtree_hashparents(job, node, root); } return arg; } static int mtree_hashsubtrees(mtree_t *t, q_t *q, int nthreads) { struct mtree_job_s job = { .tree = t }; const int subtrees = MIN(nthreads, (int)t->base); const int semcount = subtrees * 2 - 1; sem_t node[semcount]; int rc = -1; job.root = subtrees - 1; /* root of first subtree */ job.node = node; job.subtrees = subtrees; for (int i = 0; i < semcount; i++) sem_init(&node[i], 0, 0); for (int i = 0; i < subtrees; i++) { q_push(q, mtree_buildsubtree, &job); } rc = sem_wait(&node[0]); for (int i = 0; i < semcount; i++) sem_destroy(&node[i]); return rc; } static int hash_subtrees_queue(mtree_t *t, int nthreads) { pthread_t tid[nthreads]; q_t q = {0}; int rc; q_init(&q); q_pool_create(tid, nthreads, q_job_seek, &q); rc = mtree_hashsubtrees(t, &q, nthreads); q_pool_destroy(tid, nthreads); q_free(&q); return rc; } int mtree_build(mtree_t *t, void * const data, q_t *q) { int nthreads = MIN(MTREE_THREADMAX, t->base); if (!t->len) return 0; t->data = data; if (!q) return hash_subtrees_queue(t, nthreads); else return mtree_hashsubtrees(t, q, nthreads); } int mtree_init(mtree_t *t, size_t sz) { memset(t, 0, sizeof *t); t->len = sz; t->chunks = MAX(howmany(sz, MTREE_CHUNKSIZE), 1); t->base = next_pow2(t->chunks); t->nodes = (t->base << 1) - 1; t->tree = calloc(t->nodes, MTREE_HASHSIZE); return (t->tree) ? 0 : -1; } void mtree_free(mtree_t *t) { int err = errno; free(t->tree); t->data = NULL; errno = err; } librecast/src/q.c000066400000000000000000000052221502456746400142370ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2023-2024 Brett Sheffield */ #include #include int q_init(q_t *q) { astor(&q->ridx, 0); astor(&q->widx, 0); if (sem_init(&q->wlock, 0, UINT16_MAX)) return -1; return sem_init(&q->rlock, 0, 0); } int q_free(q_t *q) { return (sem_destroy(&q->wlock) | sem_destroy(&q->rlock)); } int q_trypush(q_t *q, void *(*f)(void *), void *restrict arg) { uint16_t widx; if (!q) return (errno = EINVAL), -1; if (sem_trywait(&q->wlock) == -1) return -1; widx = (uint16_t)(fetch_add(&q->widx, 1) & 0xffff); q->job[widx].f = f; q->job[widx].arg = arg; return sem_post(&q->rlock); } int q_push(q_t *q, void *(*f)(void *), void *restrict arg) { uint16_t widx; if (!q) return (errno = EINVAL), -1; if (sem_wait(&q->wlock) == -1) return -1; widx = (uint16_t)(fetch_add(&q->widx, 1) & 0xffff); q->job[widx].f = f; q->job[widx].arg = arg; return sem_post(&q->rlock); } int q_trywait(q_t *q, q_job_t *job) { uint16_t ridx; if (sem_trywait(&q->rlock) == -1) return -1; ridx = (uint16_t)(fetch_add(&q->ridx, 1) & 0xffff); job->f = q->job[ridx].f; job->arg = q->job[ridx].arg; return sem_post(&q->wlock); } int q_wait(q_t *q, q_job_t *job) { uint16_t ridx; if (sem_wait(&q->rlock) == -1) return -1; ridx = (uint16_t)(fetch_add(&q->ridx, 1) & 0xffff); job->f = q->job[ridx].f; job->arg = q->job[ridx].arg; return sem_post(&q->wlock); } void *q_job_seek(void *arg) { q_t *q = (q_t *)arg; q_job_t job = {0}; while (1) { pthread_testcancel(); if (q_wait(q, &job) == -1) continue; job.f(job.arg); } return arg; } int q_search(q_t *q, void *(*f)(void *), void *restrict arg) { /* No locks, so readers may read while we're searching, and writers may write. * If something is read while we search, we will still return a positive * match for that item, even though it is no longer in the queue. * If a writer writes we will not notice that write. * If this is a problem, an external lock will be required. */ uint16_t ridx = aload(&q->ridx); int semval; if (sem_getvalue(&q->wlock, &semval) == -1) return -1; for (int i = 0; i < UINT16_MAX - semval; i++, ridx++) { if (q->job->f == f && q->job->arg == arg) return 1; } return 0; } int q_pool_create(pthread_t tid[], int nthreads, void *(*f)(void *), void *restrict arg) { for (int z = 0; nthreads; z++) { if (pthread_create(&tid[z], NULL, f, arg)) break; nthreads--; } return nthreads; } int q_pool_destroy(pthread_t tid[], int nthreads) { for (int z = 0; nthreads; z++) { if (pthread_cancel(tid[z]) || pthread_join(tid[z], NULL)) break; nthreads--; } return nthreads; } librecast/src/router.c000066400000000000000000000521771502456746400153320ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2024 Brett Sheffield */ #include "config.h" #if defined( __linux__ ) && HAVE_RECVMMSG # define _GNU_SOURCE /* for recvmmsg() on Linux */ #endif #include #include #include #include #include #include #if HAVE_EPOLL_CREATE1 # include #else # include #endif struct edge_s { lc_router_t *r1; lc_router_t *r2; int cost; }; int lc_router_lock(lc_router_t *r) { return pthread_mutex_lock(&r->mtx); } int lc_router_trylock(lc_router_t *r) { return pthread_mutex_trylock(&r->mtx); } int lc_router_unlock(lc_router_t *r) { return pthread_mutex_unlock(&r->mtx); } int lc_router_lockpair(lc_router_t *r1, lc_router_t *r2) { int rc = -1; while (rc) { if (!pthread_mutex_lock(&r1->mtx) && (rc = pthread_mutex_trylock(&r2->mtx))) { pthread_mutex_unlock(&r1->mtx); } } return rc; } int lc_router_count(lc_ctx_t *ctx) { int n = 0; pthread_mutex_lock(&ctx->mtx); for (lc_router_t *r = ctx->router_list; r; r = r->next) n++; pthread_mutex_unlock(&ctx->mtx); return n; } int lc_router_onready(lc_router_t *r, void *(*cb)(void *), void *arg) { r->onready = cb; r->onready_arg = arg; return 0; } /* plug socket into specified port on router */ static int lc_router_port_connect(lc_router_t *r, int port, lc_socket_t *sock) { #if HAVE_EPOLL_CREATE1 struct epoll_event ev = { .data.fd = sock->sock, .events = EPOLLIN | EPOLLET }; if (epoll_ctl(r->epollfd, EPOLL_CTL_ADD, ev.data.fd, &ev) == -1) { return -1; } #endif if ((r->flags & LC_ROUTER_FLAG_RUNNING) && pthread_kill(r->recver, SIGHUP)) return -1; lc_socket_acquire(sock); astor(&sock->router, r); astor(&r->port[port], sock); /* RELEASE */ return 0; } static int lc_router_port_disconnect(lc_router_t *r, int port, lc_socket_t *sock) { #if HAVE_EPOLL_CREATE1 struct epoll_event ev = { .data.fd = sock->sock, }; if (epoll_ctl(r->epollfd, EPOLL_CTL_DEL, ev.data.fd, &ev) == -1) { return -1; } #endif if ((r->flags & LC_ROUTER_FLAG_RUNNING) && pthread_kill(r->recver, SIGHUP)) return -1; astor(&r->port[port], NULL); astor(&sock->router, NULL); /* RELEASE */ lc_socket_release(sock); return 0; } int lc_router_socket_get(lc_router_t *router, unsigned int port) { return aload(&router->port[port]->status); } int lc_router_socket_set(lc_router_t *router, unsigned int port, int status) { return (or_fetch(&router->port[port]->status, status)); } int lc_router_socket_add(lc_router_t *router, lc_socket_t *sock) { int ports = aload(&router->ports); /* ACQUIRE */ /* plug socket into next available port */ for (int i = 0; i < ports; i++) { if (!router->port[i]) { return lc_router_port_connect(router, i, sock); /* RELEASE */ } } if ((router->flags & LC_ROUTER_FLAG_FIXED) != LC_ROUTER_FLAG_FIXED) { /* all ports full, resize */ size_t off = router->ports * sizeof(lc_socket_t *); unsigned int ports = router->ports << 1; size_t sz = ports * sizeof(lc_socket_t *); int i = router->ports; lc_socket_t **port = realloc(router->port, sz); if (!port) return -1; memset(((char *)port) + off, 0, off); router->port = port; router->ports = ports; return lc_router_port_connect(router, i, sock); /* RELEASE */ } return (errno = EMLINK), -1; } int lc_router_socket_del(lc_router_t *router, lc_socket_t *sock) { int ports = aload(&router->ports); /* ACQUIRE */ for (int i = 0; i < ports; i++) { if (router->port[i] == sock) { return lc_router_port_disconnect(router, i, sock); /* RELEASE */ } } return (errno = ENOENT), -1; } int lc_router_channel_bind(lc_router_t *router, unsigned int port, lc_channel_t *chan) { lc_channel_t *copy = lc_channel_copy(router->ctx, chan); if (!copy) return -1; return lc_channel_bind(router->port[port], copy); } int lc_router_channel_unbind(lc_router_t *router, unsigned int port, lc_channel_t *chan) { /* find channel in router ctx bound to router port and with matching hash */ lc_channel_t *chan_list = aload(&router->ctx->chan_list); for (lc_channel_t *c = chan_list; c; c = c->next) { if (c->sock == router->port[port] && (!memcmp(chan->hash, c->hash, HASHSIZE))) return lc_channel_unbind(c); } return (errno = ENOENT), -1; } int lc_router_port_set(lc_router_t *router, unsigned int port, int status) { int ports = aload(&router->ports); /* ACQUIRE */ if (port == UINT_MAX) for (int i = 0; i < ports; i++) { if (router->port[i]) fetch_or_REL(&router->port[i]->status, status); /* REL */ } else if (router->port[port]) fetch_or_REL(&router->port[port]->status, status); /* REL */ else return (errno = ENOLINK), -1; return 0; } int lc_router_port_unset(lc_router_t *router, unsigned int port, int status) { int ports = aload(&router->ports); /* ACQUIRE */ if (port == UINT_MAX) for (int i = 0; i < ports; i++) { if (router->port[i]) fetch_or_REL(&router->port[i]->status, ~status); /* REL */ } else if (router->port[port]) fetch_or_REL(&router->port[port]->status, ~status); /* REL */ else return (errno = ENOLINK), -1; return 0; } int lc_router_port_down(lc_router_t *router, unsigned int port) { return lc_router_port_unset(router, port, LC_PORT_UP); } int lc_router_port_up(lc_router_t *router, unsigned int port) { return lc_router_port_set(router, port, LC_PORT_UP); } int lc_router_stop(lc_router_t *router) { pthread_t recver = aload(&router->recver); int rc = 0; if (recver) { rc = q_pool_destroy(&recver, 1); memset(&router->recver, 0, sizeof router->recver); lc_router_release(router); } fetch_or_REL(&router->flags, ~LC_ROUTER_FLAG_RUNNING); return rc; } static void *router_pkt_process(void *arg) { lc_socket_t *sock = (lc_socket_t *)arg; lc_router_t *r = sock->router; unsigned char *hash = NULL; unsigned int ridx = -1; unsigned int mask; struct pkt_s pkt; ssize_t byt; if (!r) return NULL; /* socket MUST be connected to router */ mask = r->bufs - 1; /* (1) atomically acquire router's read index (r->ridx) * (2) copy the read buffer for that ridx * (3) (CAE) if unchanged, increment ridx, else read new value and goto (2) */ while (!CAE(&r->ridx, &ridx, ridx + 1)) pkt = r->buf[ridx & mask]; /* update socket byte and packet counter (in) */ fetch_add(&sock->byt_in, pkt.len); fetch_add(&sock->pkt_in, 1); /* extract hash from packet */ lc_tlv_t *tlv_hash = (lc_tlv_t *)pkt.data; if (tlv_hash->type == LC_TLV_HASH && tlv_hash->len == HASHSIZE) hash = tlv_hash->value; /* packet forwarding */ int ports = aload(&r->ports); for (int i = 0; i < ports; i++) { lc_socket_t *port = aload(&r->port[i]); if (!port) continue; int status = aload(&port->status); if (!port || port == sock) continue; /* port must be UP and set to FWD */ if ((status & LC_PORT_UP) != LC_PORT_UP) continue; if ((status & LC_PORT_FWD) != LC_PORT_FWD) continue; /* forward only if port in flood mode or hash in OIL */ if ((status & LC_PORT_FLOOD) != LC_PORT_FLOOD && lc_socket_oil_cmp(port, hash)) continue; byt = send(r->port[i]->sock, pkt.data, pkt.len, 0); if (byt > 0) { /* update socket byte and packet counter (out) */ fetch_add(&port->byt_out, pkt.len); fetch_add(&port->pkt_out, 1); } } lc_socket_release(sock); return arg; } lc_socket_t *lc_router_port_by_fd(lc_router_t *r, int fd) { int ports = aload(&r->ports); for (int i = 0; i < ports; i++) { lc_socket_t *port = aload(&r->port[i]); if (aload(&port->sock) == fd) return port; } return NULL; } static void router_thread_recv_hup(int signo) { (void)signo; /* unused */ return; } /* router poll/recv thread * waits for data on port sockets, handles/queues for processing * by worker threads */ static void *router_thread_recv(void *arg) { lc_router_t *r = (lc_router_t *)arg; unsigned int bufs = aload(&r->bufs); #if HAVE_EPOLL_CREATE1 struct epoll_event events[bufs]; #else int ports = aload(&r->ports); struct pollfd fds[ports]; #endif struct iovec iov[bufs]; struct mmsghdr mmsg[bufs]; struct sigaction sa = {0}; unsigned int mask = bufs - 1; int msgs, nfds = 0, fd; sa.sa_handler = &router_thread_recv_hup; sa.sa_flags = SA_RESTART; if (sigaction(SIGHUP, &sa, NULL) == -1) { perror("sigaction"); return NULL; } /* initialize buffers */ memset(mmsg, 0, sizeof mmsg); for (unsigned int j = 0; j < bufs; j++) { iov[j].iov_len = sizeof r->buf[j].data; mmsg[j].msg_hdr.msg_iov = &iov[j]; mmsg[j].msg_hdr.msg_iovlen = 1; } if (r->onready) q_push(lc_ctx_q(r->ctx), r->onready, r->onready_arg); #if !defined(HAVE_EPOLL_CREATE1) reload_ports: ports = aload(&r->ports); /* ACQUIRE */ memset(fds, 0, sizeof fds); for (int i = 0; i < ports; i++) { lc_socket_t *port = r->port[i]; if (port) { lc_socket_acquire(port); fds[i].fd = port->sock; fds[i].events = POLLIN; nfds++; } } astor(&r->ports, ports); /* RELEASE */ #endif while (aload(&r->flags) & LC_ROUTER_FLAG_RUNNING) { #if HAVE_EPOLL_CREATE1 nfds = epoll_wait(r->epollfd, events, bufs, -1); if (nfds == -1) { if (errno == EINTR) continue; return NULL; } #else fd = poll(fds, nfds, -1); if (fd == -1 && errno == EINTR) goto reload_ports; #endif for (int i = 0; i < nfds; i++) { lc_socket_t *sock; unsigned int widx = aload(&r->widx) & mask; unsigned int ridx, avail; do { avail = 0; while (!avail) { /* spinlock until buffer available */ ridx = aload(&r->ridx) & mask; avail = (widx >= ridx) ? bufs - (widx - ridx) - 1 : ridx - widx - 1; } for (unsigned int j = 0, w = widx; j < avail; j++, w++) { w &= mask; iov[j].iov_base = r->buf[w].data; } #if HAVE_EPOLL_CREATE1 fd = events[i].data.fd; #else fd = fds[i].fd; #endif sock = lc_router_port_by_fd(r, fd); if (!sock) break; msgs = recvmmsg(fd, mmsg, avail, MSG_DONTWAIT, NULL); if (msgs > 0) { for (int j = 0; j < msgs; j++) { astor(&r->buf[widx].len, mmsg[j].msg_len); lc_socket_acquire(sock); q_push(lc_ctx_q(r->ctx), &router_pkt_process, sock); widx = (widx + 1) & mask; } fetch_add(&r->widx, msgs); } } while ((unsigned int)msgs == avail); } } return arg; } /* each router has one dedicated thread for monitoring ports * and receiving data. Processing of packets is handled by the * context qpool. */ int lc_router_start(lc_router_t *router) { struct pkt_s *buf = aload(&router->buf); /* ACQUIRE */ int rc; if (!buf) { router->buf = calloc(UIO_MAXIOV + 1, sizeof(struct pkt_s)); if (!router->buf) return -1; router->bufs = UIO_MAXIOV; } if (!router->ctx->q) { /* ensure we have a context queue and some threads */ int nthreads = lc_router_count(router->ctx) * ROUTER_THREADS; rc = lc_ctx_qpool_init(router->ctx, nthreads); if (rc == -1) return -1; } fetch_or_REL(&router->flags, LC_ROUTER_FLAG_RUNNING); /* RELEASE */ lc_router_acquire(router); rc = q_pool_create(&router->recver, 1, &router_thread_recv, router); if (rc) { errno = rc; return -1; } return 0; } lc_router_t *lc_router_new(lc_ctx_t *ctx, unsigned int ports, int flags) { lc_router_t *router = malloc(sizeof(lc_router_t)); if (!router) return NULL; memset(router, 0, sizeof(lc_router_t)); router->port = calloc(ports, sizeof(lc_socket_t *)); if (!router->port) goto err_free_router; router->ctx = ctx; router->ports = ports; router->flags = flags; router->readers = 1; #if HAVE_EPOLL_CREATE1 router->epollfd = epoll_create1(0); if (router->epollfd == -1) goto err_free_router; #endif pthread_mutex_init(&router->mtx, NULL); if (pthread_mutex_lock(&ctx->mtx)) goto err_free_router; router->next = ctx->router_list; ctx->router_list = router; pthread_mutex_unlock(&ctx->mtx); return router; err_free_router: free(router); return NULL; } int lc_router_connect(lc_router_t *r1, lc_router_t *r2) { lc_socket_t *sock[2]; if (lc_socketpair(r1->ctx, sock)) return -1; if (lc_router_socket_add(r1, sock[0])) return -1; if (lc_router_socket_add(r2, sock[1])) return -1; return 0; } static int has_path(lc_router_t *r1, lc_router_t *r2) { if (r1->flags & LC_ROUTER_FLAG_VISIT) return 0; r1->flags |= LC_ROUTER_FLAG_VISIT; for (int port = 0; port < (int)r1->ports; port++) { if (r1->port[port] && r1->port[port]->ttl) { if (r1->port[port]->pair->router == r2) return -1; if (has_path(r1->port[port]->pair->router, r2)) return -1; } } return 0; } /* return -1 if has path, 0 if not */ int lc_router_has_path(lc_router_t *r[], int n, lc_router_t *r1, lc_router_t *r2) { int rc; /* clear visit flags for all r[n], then perform search */ fetch_and_ACQ(&r[0]->flags, ~LC_ROUTER_FLAG_VISIT); /* ACQUIRE */ for (int i = 1; i < n; i++) r[i]->flags &= ~LC_ROUTER_FLAG_VISIT; rc = has_path(r1, r2); fetch_or_REL(&r[0]->flags, LC_ROUTER_FLAG_VISIT); /* RELEASE */ return rc; } /* return -1 if routing loop exists, 0 if not * use modified Dijkstra's algorithm to detect loop */ int lc_router_net_hasloop(lc_router_t *r[], int n) { struct vert_s { lc_router_t *r; int dist; } v[n]; int node = 0, dist; /* add all nodes to unvisited queue */ for (int i = 0; i < n; i++) { v[i].r = r[i]; v[i].dist = (!i) ? 0 : INT_MAX; } do { /* check neighbouring routers */ for (int port = 0; port < (int)v[node].r->ports; port++) { if (!v[node].r->port[port]) continue; /* find neighbour in queue */ for (int i = 0; i < n; i++) { if (v[i].r) { lc_socket_t *sock = v[node].r->port[port]; lc_socket_t *pair = v[node].r->port[port]->pair; if (v[i].r != pair->router) continue; /* ignore ports which aren't up, or have ttl=0 */ if (!sock->ttl || !pair->ttl) continue; if ((sock->status & LC_PORT_UP) != LC_PORT_UP) continue; if ((pair->status & LC_PORT_UP) != LC_PORT_UP) continue; if (v[i].dist != INT_MAX) return -1; /* loop found */ v[i].dist = v[node].dist + 1; break; } } } /* remove from queue and select next unvisited node */ v[node].r = NULL, node = 0, dist = INT_MAX; for (int i = 0; i < n; i++) { if (v[i].r && v[i].dist < dist) { node = i; dist = v[i].dist; } } } while (node); return 0; } static int edgesort(const void *p1, const void *p2) { int a = ((struct edge_s *)p1)->cost; int b = ((struct edge_s *)p2)->cost; if (a < b) return -1; if (a > b) return 1; return 0; } static int lc_router_net_connect_chain(lc_router_t *r[], int n, lc_topology_t t) { lc_socket_t *sock[2]; for (int i = (t == LC_TOPO_CHAIN) ? 1 : 0; i < n; i++) { int prev = (!i) ? n - 1 : i - 1; if (lc_socketpair(r[i]->ctx, sock)) return -1; lc_router_port_connect(r[i], 0, sock[0]); lc_router_port_connect(r[prev], 1, sock[1]); } return 0; } static int lc_router_net_connect_star(lc_router_t *r[], int n) { for (int i = 1; i < n; i++) { if (lc_router_connect(r[0], r[i])) return -1; } return 0; } static int lc_router_net_connect_mesh(lc_router_t *r[], int n) { for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { if (i < j && lc_router_connect(r[i], r[j])) return -1; } } return 0; } static int lc_router_net_connect_butterfly(lc_router_t *r[]) { if (lc_router_connect(r[0], r[2])) return -1; if (lc_router_connect(r[0], r[4])) return -1; if (lc_router_connect(r[1], r[2])) return -1; if (lc_router_connect(r[1], r[5])) return -1; if (lc_router_connect(r[2], r[3])) return -1; if (lc_router_connect(r[3], r[4])) return -1; if (lc_router_connect(r[3], r[5])) return -1; return 0; } static int lc_router_net_connect_honeycomb(lc_router_t *r[], int n) { int x = 0; int rings = n / 6; int inner = n % 6; if (!rings) return lc_router_net_connect_chain(r, n, LC_TOPO_RING); /* connect hexagons */ for (int i = 0; i < rings; i++, x += 6) { if (lc_router_net_connect_chain(&r[i * 6], 6, LC_TOPO_RING)) return -1; } /* inner triangle */ switch (inner) { case 3: if (lc_router_net_connect_chain(&r[x], inner, LC_TOPO_RING)) return -1; break; case 2: if (lc_router_net_connect_chain(&r[x], inner, LC_TOPO_CHAIN)) return -1; } /* link the rings * rule: odd => IN, even => out */ int max = (inner) ? n - inner : n - 6; for (x = 1; x < max; x += 2) { int y = x + 5; if (y >= n) break; if (lc_router_connect(r[x], r[y])) return -1; } /* handle any leftover links with inner triangle */ if (rings && inner && inner < 4) { x = rings * 6; switch (inner) { case 1: for (int y = x - 3; y < x && y < n; y += 2) { if (lc_router_connect(r[x], r[y])) return -1; } break; case 2: for (int y = x - 3, max = x + 2; x < max; x++, y += 2) { if (lc_router_connect(r[x], r[y])) return -1; } break; case 3: { int y = x - 1; x++; if (lc_router_connect(r[x], r[y])) return -1; } } } return 0; } static int lc_router_net_connect_random(lc_router_t *r[], int n) { /* randomly connect routers */ for (int i = 0; i < n; i++) { int peer, conn = 0; while (!conn) { int max = arc4random_uniform(r[i]->ports); for (int port = 0; port < max; port++) { peer = arc4random_uniform(n - 1); if (peer == i) continue; if (lc_router_connect(r[i], r[peer])) break; conn++; } } } /* ensure all routers have a path to each other */ for (int i = 0; i < n; i++) { for (int j = i + 1; j < n; j++) { if (!lc_router_has_path(r, n, r[i], r[j])) if (lc_router_connect(r[i], r[j])) return -1; } } return 0; } /* use Prim-Jarník algorithm to create minimum spanning tree */ static int lc_router_net_connect_tree(lc_router_t *r[], int n) { /* create array of edges with random edge costs */ const int edges = (n * (n - 1)) >> 1; struct edge_s edge[edges]; int e = 0; for (int i = 0; i < n; i++) { for (int j = i + 1; j < n; j++) { edge[e].r1 = r[i]; edge[e].r2 = r[j]; edge[e].cost = arc4random_uniform(n) + 1; e++; } } qsort(edge, edges, sizeof(struct edge_s), edgesort); /* mark all nodes unvisited except r0 */ r[0]->flags |= LC_ROUTER_FLAG_VISIT; for (int i = 1; i < n; i++) r[i]->flags &= ~LC_ROUTER_FLAG_VISIT; /* select lowest edge that connects to visited */ for (int v = 0; v < n; v++) { for (int e = 0; e < edges; e++) { if ((edge[e].r1->flags & LC_ROUTER_FLAG_VISIT) && !(edge[e].r2->flags & LC_ROUTER_FLAG_VISIT)) { edge[e].r2->flags |= LC_ROUTER_FLAG_VISIT; if (lc_router_connect(edge[e].r1, edge[e].r2)) return -1; } else if (!(edge[e].r1->flags & LC_ROUTER_FLAG_VISIT) && (edge[e].r2->flags & LC_ROUTER_FLAG_VISIT)) { edge[e].r1->flags |= LC_ROUTER_FLAG_VISIT; if (lc_router_connect(edge[e].r1, edge[e].r2)) return -1; } else continue; break; } } return 0; } int lc_router_net_connect(lc_router_t *r[], int n, lc_topology_t t, int flags) { (void)flags; /* unused, at present */ switch (t) { case LC_TOPO_RING: case LC_TOPO_CHAIN: return lc_router_net_connect_chain(r, n, t); case LC_TOPO_STAR: return lc_router_net_connect_star(r, n); case LC_TOPO_MESH: return lc_router_net_connect_mesh(r, n); case LC_TOPO_BUTTERFLY: return lc_router_net_connect_butterfly(r); case LC_TOPO_HONEYCOMB: return lc_router_net_connect_honeycomb(r, n); case LC_TOPO_RANDOM: return lc_router_net_connect_random(r, n); case LC_TOPO_TREE: return lc_router_net_connect_tree(r, n); case LC_TOPO_NONE: return 0; default: return (errno = ENOSYS), -1; } } static unsigned int default_topology_ports(lc_topology_t t, int n) { switch (t) { case LC_TOPO_CHAIN: case LC_TOPO_RING: return 2; /* one for each neighbour */ case LC_TOPO_TREE: case LC_TOPO_STAR: return 1; /* leaf nodes need one port, root=auto */ case LC_TOPO_RANDOM: case LC_TOPO_MESH: return n - 1; case LC_TOPO_BUTTERFLY: case LC_TOPO_HONEYCOMB: return 3; default: return 0; } } int lc_router_net(lc_ctx_t *ctx, lc_router_t *r[], int n, lc_topology_t t, unsigned int ports, int flags) { int i, errsv; if (t == LC_TOPO_BUTTERFLY && n != 6) return (errno = EINVAL), -1; if (!ports) ports = default_topology_ports(t, n); for (i = 0; i < n; i++) { r[i] = lc_router_new(ctx, ports, flags); if (!r[i]) goto err_free; } return lc_router_net_connect(r, n, t, flags); err_free: errsv = errno; while (i--) { lc_router_free(r[i]); } errno = errsv; return -1; } void lc_router_release(lc_router_t *r) { /* decrease reference count, fetch updated value */ int refs = add_fetch(&r->readers, -1); int deleted = aload(&r->deleted); if (!refs && deleted == DELETE_LATER) { /* no readers left, try to delete */ if (CAE(&r->deleted, &deleted, DELETE_IN_PROGRESS)) { for (int i = 0; i < (int)r->ports; i++) { lc_socket_t *port = aload(&r->port[i]); if (port) lc_socket_release(port); } if (r->buf) free(r->buf); free(r->port); free(r); } } } lc_router_t *lc_router_acquire(lc_router_t *r) { if (!r || aload(&r->deleted)) return NULL; fetch_add(&r->readers, 1); /* increase reference count */ return r; } static void router_unlink(lc_router_t *router) { pthread_mutex_lock(&router->ctx->mtx); lc_router_t *prev = NULL; for (lc_router_t *p = aload(&router->ctx->router_list); p; p = p->next) { if (p == router) { if (prev) prev->next = p->next; else astor(&router->ctx->router_list, p->next); break; } prev = p; } pthread_mutex_unlock(&router->ctx->mtx); } void lc_router_free(lc_router_t *router) { int err = errno; if (!router) return; router_unlink(router); lc_router_stop(router); int deleted = 0; if (CAE(&router->deleted, &deleted, DELETE_LATER)) lc_router_release(router); errno = err; } librecast/src/sync.c000066400000000000000000001160641502456746400147620ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2023-2025 Brett Sheffield */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #ifdef HAVE_SYS_TYPES_H #include #endif #ifdef HAVE_UTIME_H #include #endif #define DEBUG_SYNC(...) if (lctx->debug & LCTX_DEBUG_SYNCFILE) fprintf(lctx->stream, __VA_ARGS__) static sem_t semjob; struct syncjob { sem_t done; lc_ctx_t *lctx; lc_stat_t *stats; unsigned char *hash; unsigned char *ptr; ssize_t rc; size_t sz; int flags; int err; }; /* wrapper for pthread_cleanup_push */ inline static void _lc_channel_part(lc_channel_t *chan) { (void)lc_channel_part(chan); } /* return number of bits set in bitmap (Hamming Weight) */ #ifdef HAVE_RQ_OTI static unsigned int hamm(unsigned char *map, size_t len) { unsigned int c = 0; if (!map) return c; while (len--) for (char v = map[len]; v; c++) v &= v - 1; return c; } /* receive net_tree_t (either a merkle tree or directory tree hashes + metadata) */ static ssize_t lc_recvnettree(lc_ctx_t *lctx, unsigned char *hash, net_tree_t **data, lc_stat_t *stats, lc_sync_options_t *opt, int flags) { (void)opt, (void)flags; /* unused */ rq_oti_t oti; rq_scheme_t scheme; lc_socket_t *sock; lc_channel_t *chan; ssize_t rc = -1; uint64_t F; uint16_t T; int err = 0; /* join channel with FEC encoding. Trees are sent with OTI header */ sock = lc_socket_new(lctx); if (!sock) goto err_errno; chan = lc_channel_hash(lctx, hash, HASHSIZE, LC_DEFAULT_FLAGS, LC_DEFAULT_PORT); if (!chan) goto err_socket_close; if (lc_channel_bind(sock, chan) == -1) { err = errno; goto err_channel_free; } lc_channel_coding_set(chan, lctx->coding | LC_CODE_FEC_RQ | LC_CODE_FEC_OTI); if (lc_channel_join(chan) == -1) { err = errno; goto err_channel_free; } /* peek at OTI header of first packet, allocate buffer */ if ((rc = lc_channel_oti_peek(chan, &oti, &scheme)) == -1) { err = errno; goto err_channel_part; } F = rq_oti_F(oti); T = rq_oti_T(oti); if (T != LC_DEFAULT_RQ_T) { err= EBADMSG; rc = -1; goto err_channel_part; } *data = malloc(F); if (!*data) { err = errno; goto err_channel_part; } /* receive tree */ rc = lc_channel_recv(chan, *data, (size_t)F, 0); if (rc == -1) { err = errno; free(*data); } else { if (stats) stats->byt_gross += rc; (*data)->size = be64toh((*data)->size); (*data)->namesz = ntohs((*data)->namesz); rc = (ssize_t)F; } /* clean up */ err_channel_part: lc_channel_part(chan); err_channel_free: lc_channel_free(chan); err_socket_close: lc_socket_close(sock); err_errno: if (err) errno = err; return rc; } ssize_t lc_recvdir(lc_ctx_t *lctx, unsigned char *hash, net_tree_t **dir, lc_stat_t *stats, lc_sync_options_t *opt, int flags) { ssize_t rc; rc = lc_recvnettree(lctx, hash, dir, stats, opt, flags); if (rc == -1) return -1; if (((*dir)->mode & S_IFMT) == S_IFDIR) return rc; return (errno = ENOTDIR), -1; } /* receive rest of multi-part tree */ static size_t lc_recvmultiparttree(lc_ctx_t *lctx, mtree_t *tree, size_t byt, size_t len, size_t parts, struct stat *sb, char *sharepath) { lc_socket_t *sock = NULL; lc_channel_t *chan = NULL; unsigned char root[HASHSIZE] = {0}; ssize_t rc = 0; uint8_t *ptr = (uint8_t *)tree->tree; int err = 0, ret; for (size_t z = 1; z < parts; z++) { ptr += byt; len -= byt; mdex_tree_hash_sb(root, HASHSIZE, tree, z, sb, sharepath); sock = lc_socket_new(lctx); if (!sock) { err = errno; break; } chan = lc_channel_hash(lctx, root, HASHSIZE, LC_DEFAULT_FLAGS, LC_DEFAULT_PORT); if (!chan) { err = errno; goto err_socket_close; } ret = lc_channel_bind(sock, chan); if (ret == -1) { err = errno; goto err_channel_free; } lc_channel_coding_set(chan, lctx->coding | LC_CODE_FEC_RQ | LC_CODE_FEC_OTI); ret = lc_channel_join(chan); if (ret == -1) { err = errno; goto err_channel_free; } byt = MIN(len, MTREE_CHUNKSIZE); rc = lc_channel_recv(chan, ptr, byt, 0); lc_channel_part(chan); err_channel_free: lc_channel_free(chan); err_socket_close: lc_socket_close(sock); if (err) break; } if (err) errno = err; return rc; } static ssize_t buildtree(ssize_t rc, lc_ctx_t *lctx, mtree_t *tree, net_tree_t *data) { if (mtree_init(tree, data->size) == 0) { size_t byt = rc - sizeof(struct net_tree_s) - data->namesz; size_t len = tree->nodes * HASHSIZE + sizeof(struct net_tree_s) + data->namesz; size_t parts = howmany(len, MTREE_CHUNKSIZE); memcpy(tree->tree, data->tree + data->namesz, byt); len -= sizeof(struct net_tree_s) + data->namesz; if (parts > 1) { struct stat sb = { .st_atim.tv_sec = data->atime_s, .st_atim.tv_nsec = data->atime_n, .st_mtim.tv_sec = data->mtime_s, .st_mtim.tv_nsec = data->mtime_n, .st_mode = data->mode, .st_uid = data->uid, .st_gid = data->gid, }; char *sharepath = strndup((char *)data->tree, (size_t)data->namesz); if (!sharepath) return -1; rc = lc_recvmultiparttree(lctx, tree, byt, len, parts, &sb, sharepath); free(sharepath); if (rc == -1) return -1; } rc = mtree_verify(tree); if (rc == -1) errno = ENOMSG; } return rc; } ssize_t lc_recvtree(lc_ctx_t *lctx, unsigned char *hash, mtree_t *tree, lc_stat_t *stats, lc_sync_options_t *opt, int flags) { net_tree_t *data = NULL; ssize_t rc; int err = 0; rc = lc_recvnettree(lctx, hash, &data, stats, opt, flags); if (rc == -1) return -1; if ((data->mode & S_IFMT) == S_IFDIR) err = EISDIR; else if ((size_t)rc < sizeof(struct net_tree_s)) err = ENOMSG; else if (buildtree(rc, lctx, tree, data) == -1) err = errno; free(data); if (err) errno = err; return rc; } static ssize_t lc_sendnettree(lc_ctx_t *lctx, unsigned char *hash, const net_tree_t *data, const size_t sz, lc_stat_t *stats, lc_sync_options_t *opt, int flags) { (void)stats, (void)opt, (void)flags; /* unused */ lc_socket_t *sock; lc_channel_t *chan; ssize_t rc; /* send tree with FEC encoding */ sock = lc_socket_new(lctx); if (!sock) return -1; pthread_cleanup_push((void (*)(void *))lc_socket_close, sock); chan = lc_channel_hash(lctx, hash, HASHSIZE, LC_DEFAULT_FLAGS, LC_DEFAULT_PORT); if (!chan) { rc = -1; goto err_socket_close; } pthread_cleanup_push((void (*)(void *))lc_channel_free, chan); if (lc_channel_bind(sock, chan) == -1) { rc = -1; goto err_channel_free; } if ((flags & NET_LOOPBACK) && lc_socket_loop(sock, 1) == -1) { rc = -1; goto err_channel_free; } lc_channel_coding_set(chan, lctx->coding | LC_CODE_FEC_RQ | LC_CODE_FEC_OTI); rc = lc_channel_send(chan, data, sz, 0); while (rc > 0) rc = lc_channel_send(chan, NULL, 0, 0); /* clean up */ err_channel_free: pthread_cleanup_pop(1); /* lc_channel_free */ err_socket_close: pthread_cleanup_pop(1); /* lc_socket_close */ return rc; } ssize_t lc_senddir(lc_ctx_t *lctx, unsigned char *hash, net_tree_t *dir, lc_stat_t *stats, lc_sync_options_t *opt, int flags) { size_t sz = sizeof (net_tree_t) + dir->size; ssize_t rc; dir->size = htobe64(dir->size); rc = lc_sendnettree(lctx, hash, dir, sz, stats, opt, flags); return rc; } ssize_t lc_sendtree(lc_ctx_t *lctx, unsigned char *hash, const mtree_t *tree, lc_stat_t *stats, lc_sync_options_t *opt, int flags) { net_tree_t *data; size_t hashsz = tree->nodes * HASHSIZE; size_t sz = sizeof (net_tree_t) + hashsz; ssize_t rc; /* prepare tree for sending */ data = malloc(sz); if (!data) return -1; memset(data, 0, sz); pthread_cleanup_push(free, data); data->size = htobe64(tree->len); memcpy(data->tree, tree->tree, hashsz); rc = lc_sendnettree(lctx, hash, data, sz, stats, opt, flags); pthread_cleanup_pop(1); /* free(data) */ return rc; } ssize_t lc_recvchunk(lc_ctx_t *lctx, unsigned char *hash, void *data, const size_t len, lc_stat_t *stats, lc_sync_options_t *opt, int flags) { (void)opt; lc_socket_t *sock; lc_channel_t *chan; ssize_t rc; sock = lc_socket_new(lctx); if (!sock) { rc = -1; goto err_exit; } pthread_cleanup_push((void (*)(void *))lc_socket_close, sock); chan = lc_channel_hash(lctx, hash, HASHSIZE, LC_DEFAULT_FLAGS, LC_DEFAULT_PORT); if (!chan) { rc = -1; goto err_socket_close; } pthread_cleanup_push((void (*)(void *))lc_channel_free, chan); if (lc_channel_bind(sock, chan) == -1) { rc = -1; goto err_channel_free; } lc_channel_coding_set(chan, lctx->coding | LC_CODE_FEC_RQ); if (lc_channel_join(chan) == -1) { rc = -1; goto err_channel_free; } pthread_cleanup_push((void (*)(void *))_lc_channel_part, chan); rc = lc_channel_recv(chan, data, len, flags); if (stats && rc > 0) add_fetch(&stats->byt_gross, rc); pthread_cleanup_pop(1); /* lc_channel_part */ err_channel_free: pthread_cleanup_pop(1); /* lc_channel_free */ err_socket_close: pthread_cleanup_pop(1); /* lc_socket_close */ err_exit: return rc; } ssize_t lc_sendchunk(lc_ctx_t *lctx, unsigned char *hash, const void *data, const size_t len, lc_stat_t *stats, lc_sync_options_t *opt, int flags) { (void)stats, (void)opt, (void)flags; /* unused */ lc_socket_t *sock; lc_channel_t *chan; ssize_t rc; sock = lc_socket_new(lctx); if (!sock) { rc = -1; goto err_exit; } pthread_cleanup_push((void (*)(void *))lc_socket_close, sock); chan = lc_channel_hash(lctx, hash, HASHSIZE, LC_DEFAULT_FLAGS, LC_DEFAULT_PORT); if (!chan) { rc = -1; goto err_socket_close; } pthread_cleanup_push((void (*)(void *))lc_channel_free, chan); if (lc_channel_bind(sock, chan) == -1) { rc = -1; goto err_channel_free; } if ((flags & NET_LOOPBACK) && lc_socket_loop(sock, 1) == -1) { rc = -1; goto err_channel_free; } lc_channel_coding_set(chan, lctx->coding | LC_CODE_FEC_RQ); rc = lc_channel_send(chan, data, len, 0); while (rc > 0) rc = lc_channel_send(chan, NULL, 0, 0); err_channel_free: pthread_cleanup_pop(1); /* lc_channel_free */ err_socket_close: pthread_cleanup_pop(1); /* lc_socket_close */ err_exit: return rc; } #ifdef HAVE_MLD static ssize_t share_send_data(lc_share_t *share, struct in6_addr *grp, struct mdex_mem_s *mem, int coding) { lc_socket_t *sock; lc_channel_t *chan; ssize_t rc = -1; sock = lc_socket_new(share->lctx); if (!sock) return -1; chan = lc_channel_init_grp(share->lctx, grp, LC_DEFAULT_PORT); if (!chan) goto err_socket_close; if (share->ifx) lc_socket_bind(sock, share->ifx); if (lc_channel_bind(sock, chan) == -1) goto err_channel_free; if ((share->flags & LC_SHARE_LOOPBACK) && lc_socket_loop(sock, 1) == -1) goto err_channel_free; lc_channel_coding_set(chan, share->lctx->coding | coding); rc = lc_channel_send(chan, mem->data, mem->size, 0); if (rc == -1 || !chan->rq) goto err_channel_free; if (share->stats) { share->stats->byt_gross += rc; share->stats->byt_info += mem->size; share->stats->pkts_io++; } for (int i = 1; i < rq_KP(chan->rq) + RQ_OVERHEAD * 2; i++) { rc = lc_channel_send(chan, NULL, 0, 0); if (rc == -1) break; if (share->stats) { share->stats->byt_gross += rc; share->stats->pkts_io++; } } err_channel_free: lc_channel_free(chan); err_socket_close: lc_socket_close(sock); return rc; } #endif /* HAVE_MLD */ static char *concat_mdex_root_file(const char *root, const char *file) { size_t rlen = strlen(root); size_t flen = strlen(file); char *path = malloc(rlen + flen + 2); if (!path) return NULL; strcpy(path, root); path[rlen] = '/'; strcpy(path + rlen + 1, file); return path; } static ssize_t share_send_file(lc_share_t *share, struct in6_addr *grp, mdex_entry_t *entry, int coding) { lc_ctx_t *lctx = share->lctx; const struct mdex_file_s *file = &entry->file; struct mdex_mem_s mem = { .size = file->size }; struct stat sbs = {0}; char *smap = NULL; ssize_t rc = -1; size_t sz = 0; char *path = concat_mdex_root_file(share->mdex->rootdir, file->file.name); if (!path) return -1; if ((smap = lc_mmapfile(path, &sz, PROT_READ, MAP_PRIVATE, 0, &sbs)) == MAP_FAILED) goto err_free_path; mem.data = smap + file->off; DEBUG_SYNC("%s\n", file->file.name); rc = share_send_data(share, grp, &mem, coding); munmap(smap, sz); err_free_path: free(path); return rc; } static ssize_t share_send_dir(lc_share_t *share, struct in6_addr *grp, mdex_entry_t *entry, int coding) { lc_ctx_t *lctx = share->lctx; const struct mdex_file_s *file = &entry->file; net_tree_t *dir; struct mdex_mem_s mem = {0}; unsigned char *tree; size_t namesz = strlen(file->file.name); size_t sz; ssize_t rc = -1; sz = sizeof(net_tree_t) + namesz + sizeof(hash_t) * file->size; dir = calloc(1, sz); if (!dir) return -1; if (namesz) memcpy(dir->tree, file->file.name, namesz); tree = dir->tree + namesz; if (file->size) memcpy(tree, file->file.dir, sizeof(hash_t) * file->size); dir->size = htobe64(sz); dir->mtime_s = file->file.sb->st_mtim.tv_sec; dir->mtime_n = file->file.sb->st_mtim.tv_nsec; dir->atime_s = file->file.sb->st_atim.tv_sec; dir->atime_n = file->file.sb->st_atim.tv_nsec; dir->mode = file->file.sb->st_mode; dir->uid = file->file.sb->st_uid; dir->gid = file->file.sb->st_gid; dir->namesz = htons(namesz); mem.data = dir; mem.size = sz; DEBUG_SYNC("%s\n", file->file.name); rc = share_send_data(share, grp, &mem, coding); free(dir); return rc; } /* readlink(), then pack filename + link data into dir->tree payload and set set * header metadata */ static ssize_t share_send_link(lc_share_t *share, struct in6_addr *grp, mdex_entry_t *entry, int coding) { lc_ctx_t *lctx = share->lctx; const struct mdex_file_s *file = &entry->file; net_tree_t *dir; char *buf, *linkpath = NULL; unsigned char *tree; struct mdex_mem_s mem = {0}; size_t namesz = strlen(file->file.name); size_t sz; ssize_t rc = -1; long int path_max; #ifdef PATH_MAX path_max = PATH_MAX; #else path_max = pathconf(name, _PC_PATH_MAX); if (path_max <= 0) path_max = 1024; #endif buf = malloc(path_max); if (!buf) return -1; linkpath = concat_mdex_root_file(share->mdex->rootdir, file->file.name); if (!linkpath) goto err_free_buf; rc = readlink(linkpath, buf, (size_t)path_max); if (rc == -1) goto err_free_linkpath; sz = sizeof(net_tree_t) + namesz + (size_t)rc; dir = calloc(1, sz); if (!dir) goto err_free_linkpath; if (namesz) memcpy(dir->tree, file->file.name, namesz); tree = dir->tree + namesz; memcpy(tree, buf, (size_t)rc); dir->size = htobe64(sz); dir->mtime_s = file->file.sb->st_mtim.tv_sec; dir->mtime_n = file->file.sb->st_mtim.tv_nsec; dir->atime_s = file->file.sb->st_atim.tv_sec; dir->atime_n = file->file.sb->st_atim.tv_nsec; dir->mode = file->file.sb->st_mode; dir->uid = file->file.sb->st_uid; dir->gid = file->file.sb->st_gid; dir->namesz = htons(namesz); mem.data = dir; mem.size = sz; DEBUG_SYNC("%s\n", file->file.name); rc = share_send_data(share, grp, &mem, coding); free(dir); err_free_linkpath: free(linkpath); err_free_buf: free(buf); return rc; } static void *share_send_thread(void *arg) { lc_share_t *share = lc_share_acquire((lc_share_t *)arg); if (!share) return NULL; q_job_t job = {0}; while (1) { pthread_testcancel(); if (q_wait(&share->q, &job) == -1) continue; if (job.arg) { pthread_cleanup_push(free, job.arg); int coding = share->lctx->coding | LC_CODE_FEC_RQ; struct qentry_s *qe = (struct qentry_s *)job.arg; mdex_entry_t *entry = &qe->entry; struct in6_addr *grp = &qe->grp; if (entry->type & MDEX_RAND) { coding |= LC_CODE_FEC_RAND; } if (entry->type & MDEX_OTI) { coding |= LC_CODE_FEC_OTI; } if (entry->type & MDEX_PTR) { share_send_data(share, grp, &entry->ptr, coding); } else if (entry->type & MDEX_FILE) { share_send_file(share, grp, entry, coding); } else if (entry->type & MDEX_DIR) { share_send_dir(share, grp, entry, coding); } else if (entry->type & MDEX_LINK) { share_send_link(share, grp, entry, coding); } pthread_cleanup_pop(1); /* free(entry) */ } } return NULL; } /* when MLD detects a JOIN, check mdex for matching group, and queue for sending */ static void share_watch_callback(mld_watch_t *watch) { lc_share_t *share = (lc_share_t *)mld_watch_arg(watch); mdex_entry_t entry = {0}; unsigned char hash[HASHSIZE]; struct in6_addr *grp = mld_watch_grp(watch); memcpy(hash, &(grp->s6_addr[2]), 14); if (!mdex_get(share->mdex, hash, 14, &entry)) { if (!q_search(&share->q, NULL, &entry)) { struct qentry_s *arg = malloc(sizeof (struct qentry_s)); if (arg) { arg->grp = *grp; arg->entry = entry; q_push(&share->q, NULL, arg); } } } } lc_share_t * lc_share(lc_ctx_t *lctx, mdex_t *mdex, unsigned int ifx, lc_stat_t *stats, lc_sync_options_t *opt, int flags) { #ifdef HAVE_MLD (void)stats, (void)opt, (void)flags; /* unused */ const int nthread_send = SYNC_SEND_THREADS; lc_share_t *share; int err = 0; /* allocate & initialize share */ share = calloc(1, sizeof (lc_share_t)); if (!share) return NULL; share->readers = 1; share->tsend = calloc(nthread_send, sizeof(pthread_t)); if (!share->tsend) { err = errno; goto err_free_share; } share->lctx = lctx; share->stats = stats; share->mdex = mdex; share->ifx = ifx; share->flags = flags; /* initialize MLD and watch callback */ share->mld = mld_init(0); if (!share->mld) { err = errno; goto err_free_tsend; } share->watch = mld_watch_add(share->mld, ifx, NULL, share_watch_callback, share, MLD_EVENT_JOIN); if (!share->watch) { err = errno; goto err_free_mld; } if (!mld_start(share->mld)) { err = errno; goto err_free_mld; } /* initialize send queue and start send thread(s) */ if (q_init(&share->q) == -1) { err = errno; goto err_free_mld; } err = q_pool_create(share->tsend, nthread_send, share_send_thread, share); share->nthread_send = nthread_send - err; /* number of threads actually created */ if (!share->nthread_send) { err = errno; goto err_free_q; } return share; err_free_q: (void)q_free(&share->q); err_free_mld: free(share->mld); err_free_tsend: free(share->tsend); err_free_share: free(share); if (err) errno = err; return NULL; #else (void)lctx; (void)mdex; (void)ifx; (void)stats; (void)opt; (void)flags; /* unused */ return (errno = ENOTSUP), NULL; #endif /* HAVE_MLD */ } lc_share_t *lc_share_acquire(lc_share_t *share) { if (!share || aload(&share->deleted)) return NULL; fetch_add(&share->readers, 1); /* increase reference count */ return share; } void lc_share_release(lc_share_t *share) { /* decrease reference count, fetch updated value */ int refs = add_fetch(&share->readers, -1); int deleted = aload(&share->deleted); if (!refs && deleted == DELETE_LATER) { /* no readers left, try to delete */ if (CAE(&share->deleted, &share, DELETE_IN_PROGRESS)) { free(share); } } } void lc_unshare(lc_share_t *share) { #ifdef HAVE_MLD int err = errno; q_job_t job = {0}; q_pool_destroy(share->tsend, share->nthread_send); while (share->nthread_send--) lc_share_release(share); free(share->tsend); while (!q_trywait(&share->q, &job)) free(job.arg); (void)q_free(&share->q); mld_stop(share->mld); mld_watch_del(share->watch); mld_free(share->mld); int deleted = 0; if (CAE(&share->deleted, &deleted, DELETE_LATER)) lc_share_release(share); errno = err; #else (void)share; #endif } #endif /* HAVE_LIBLCRQ */ int lc_memsync(void *dst, void *src, const size_t n, q_t *q, lc_stat_t *stats, lc_sync_options_t *opt, int flags) { (void)opt, (void)flags; /* unused */ mtree_t stree = {0}, dtree = {0}; unsigned char *map; int rc = -1, err = 0; if (!n) return (errno = EINVAL), -1; /* create mtree for src and dest */ if (mtree_init(&stree, n) == -1) { err = errno; goto err_errno; } if (mtree_init(&dtree, n) == -1) { err = errno; goto err_free_stree; } /* build trees */ if (mtree_build(&stree, src, q) == -1) { err = errno; goto err_free_dtree; } if (mtree_build(&dtree, dst, q) == -1) { err = errno; goto err_free_dtree; } /* diff trees */ map = mtree_diff_subtree(&stree, &dtree, 0, 1); if (!map) { err = errno; goto err_free_dtree; } /* sync data */ for (size_t z = 0; z < stree.chunks; z++) { if (isset(map, z)) { size_t off = z * MTREE_CHUNKSIZE; size_t len = MIN(MTREE_CHUNKSIZE, n - off); memcpy((char *)dst + off, (char *)src + off, len); if (stats) stats->byt_info += len; /* Information Rate */ } } /* clean up & return */ free(map); err_free_dtree: rc = 0; mtree_free(&dtree); err_free_stree: mtree_free(&stree); err_errno: if (err) errno = err; return rc; } void *lc_mmapfile(const char *pathname, size_t *len, int prot, int flags, off_t offset, struct stat *sb) { char *map = MAP_FAILED; mode_t mode = (sb->st_mode) ? sb->st_mode : 0600; int oflag = (prot & PROT_WRITE) ? O_RDWR | O_CREAT : O_RDONLY; int fd; /* if we're not creating a file, check first if this is a directory or symlink */ if (!(prot & PROT_WRITE) && !sb->st_ino && lstat(pathname, sb) == -1) return map; if (!*len && !sb->st_size) return (errno = ENODATA), map; if ((sb->st_mode & S_IFMT) == S_IFDIR) return (errno = EISDIR), map; if ((sb->st_mode & S_IFMT) == S_IFLNK) return (errno = EMLINK), map; /* not a directory or symlink, continue with mapping */ if ((fd = open(pathname, oflag, mode)) == -1) return map; if (*len && ftruncate(fd, *len) == -1) goto err_close_fd; if (!*len) *len = sb->st_size; map = mmap(NULL, *len, prot, flags, fd, offset); err_close_fd: close(fd); return map; } static int utimeset(const char *pathname, struct timespec *atime, struct timespec *mtime) { #ifdef HAVE_UTIMENSAT struct timespec t[2] = {0}; if (atime) t[0] = *atime; if (mtime) t[1] = *mtime; return utimensat(AT_FDCWD, pathname, t, AT_SYMLINK_NOFOLLOW); #elif defined(HAVE_UTIMES) struct timeval t[2] = {0}; if (atime) { t[0].tv_sec = atime->tv_sec; t[0].tv_usec = atime->tv_nsec / 1000; } if (mtime) { t[1].tv_sec = mtime->tv_sec; t[1].tv_usec = mtime->tv_nsec / 1000; } return utimes(pathname, t); #else return (errno = ENOTSUP), -1; #endif } static int setfilestat(const char *pathname, struct stat *sb, int flags) { struct timespec *atime, *mtime; int uid, gid; int rc = 0; if (!sb) return (errno = EINVAL), -1; atime = (flags & SYNC_ATIME) ? &sb->st_atim : NULL; mtime = (flags & SYNC_MTIME) ? &sb->st_mtim : NULL; uid = (flags & SYNC_OWNER) ? (int)sb->st_uid : -1; gid = (flags & SYNC_GROUP) ? (int)sb->st_gid : -1; if ((uid | gid) != -2) rc += chown(pathname, uid, gid); if (flags & SYNC_MODE) rc += chmod(pathname, sb->st_mode & 0777); if (atime || mtime) rc += utimeset(pathname, atime, mtime); return rc; } #ifdef HAVE_RQ_OTI static int setfilemeta(const char *pathname, net_tree_t *data, int flags) { struct timespec atime = {0}; struct timespec mtime = {0}; int uid, gid; int rc = 0; if (flags & SYNC_ATIME) { atime.tv_sec = data->atime_s; atime.tv_nsec = data->atime_n; } if (flags & SYNC_MTIME) { mtime.tv_sec = data->mtime_s; mtime.tv_nsec = data->mtime_n; } uid = (flags & SYNC_OWNER) ? (int)data->uid : -1; gid = (flags & SYNC_GROUP) ? (int)data->gid : -1; if ((uid | gid) != -2) rc += chown(pathname, uid, gid); if (flags & SYNC_MODE) rc += chmod(pathname, data->mode & 0777); if ((flags & SYNC_ATIME) || (flags & SYNC_MTIME)) rc += utimeset(pathname, &atime, &mtime); return rc; } #endif static int syncdirlocal(mdex_t *sdex, mdex_t *ddex, const char *src, const char *dst, size_t top, q_t *q, lc_stat_t *stats, lc_sync_options_t *opt, int flags); static int copydirlocal(mdex_t *sdex, mdex_t *ddex, mdex_hash_t sdir, size_t top, q_t *q, lc_stat_t *stats, lc_sync_options_t *opt, int flags) { mdex_entry_t se; char *tmp; char *dname = NULL; char *sharepath = NULL; struct stat sb = {0}; int srctype; int rc; /* first, find the source entry */ rc = mdex_get(sdex, sdir, sizeof(mdex_hash_t), &se); if (rc == -1) return -1; srctype = se.type & 0xffff; if (srctype == MDEX_PTR) { unsigned char hash[HASHSIZE]; mtree_t mtree; net_tree_t *data = se.ptr.data; data->size = be64toh(data->size); data->namesz = ntohs(data->namesz); tmp = strndup((char *)data->tree, (size_t)data->namesz); if (!tmp) return -1; sharepath = mdex_sharepath(sdex, tmp); free(tmp); if (!sharepath) return -1; rc = mtree_init(&mtree, data->size); if (rc == -1) goto err_free_sharepath; memcpy(mtree.tree, data->tree + data->namesz, (size_t)mtree.nodes * (size_t)HASHSIZE); sb.st_atim.tv_sec = data->atime_s; sb.st_atim.tv_nsec = data->atime_n; sb.st_mtim.tv_sec = data->mtime_s; sb.st_mtim.tv_nsec = data->mtime_n; sb.st_mode = data->mode; sb.st_uid = data->uid; sb.st_gid = data->gid; rc = mtree_verify(&mtree); if (rc != 0) goto err_free_sharepath; mdex_tree_hash_sb(hash, HASHSIZE, &mtree, 0, &sb, sharepath); rc = mdex_get(sdex, hash, HASHSIZE, &se); mtree_free(&mtree); if (rc != 0) goto err_free_sharepath; } /* build destination filename */ if (!sharepath) sharepath = se.file.file.name; rc = snprintf(NULL, 0, "%s/%s", ddex->rootdir, sharepath) + 1; dname = malloc(rc); snprintf(dname, rc, "%s/%s", ddex->basedir, sharepath + top); switch (srctype) { case MDEX_DIR: rc = syncdirlocal(sdex, ddex, sharepath, dname, top, q, stats, opt, flags); break; case MDEX_PTR: rc = lc_syncfilelocal(dname, sharepath, q, stats, opt, flags); break; default: free(dname); return (errno = ENOTSUP), -1; } setfilestat(dname, se.file.file.sb, flags); free(dname); return rc; err_free_sharepath: free(sharepath); return -1; } static int syncdirlocal(mdex_t *sdex, mdex_t *ddex, const char *src, const char *dst, size_t top, q_t *q, lc_stat_t *stats, lc_sync_options_t *opt, int flags) { mdex_hash_t *sdir, *ddir = NULL; mdex_entry_t sentry, dentry = {0}; int rc = mdex_getalias(sdex, src, &sentry); if (rc == -1) return -1; sdir = sentry.file.file.dir; rc = mdex_getalias(ddex, dst, &dentry); if (rc == -1) { /* destination doesn't exist. Create */ rc = mkdir(dst, 0755); if (rc == -1) return -1; } else ddir = dentry.file.file.dir; if (sdir == NULL && ddir == NULL) return 0; if (sentry.file.size == dentry.file.size) { size_t sz = sentry.file.size * sizeof(*sdir); if (!memcmp(sdir, ddir, sz)) return 0; /* directories match */ } /* sync each directory entry */ for (size_t i = 0; i < sentry.file.size; i++) { int found = 0; if (ddir) for (size_t j = 0; j < sentry.file.size; j++) { if (!memcmp(sdir[i], ddir[j], sizeof(mdex_hash_t))) { found = 1; break; } } if (!found) { rc = copydirlocal(sdex, ddex, sdir[i], top, q, stats, opt, flags); if (rc == -1) return -1; } } rc = setfilestat(dst, sentry.file.file.sb, flags); return 0; } static int syncrecursive_local(const char *dst, const char *src, q_t *q, lc_stat_t *stats, lc_sync_options_t *opt, int flags) { (void)stats, (void)opt; /* unused */ mdex_t *sdex, *ddex; int err = 0; int rc = -1; int mflags = 0; if (flags & SYNC_RECURSE) mflags |= MDEX_RECURSE; /* index source directory */ sdex = mdex_init(512); if (!sdex) return -1; rc = mdex_addfile(sdex, src, q, mflags); if (rc) { err = errno; goto err_sdex_free; } /* index destination directory */ ddex = mdex_init(512); if (!ddex) { err = errno; goto err_sdex_free; } rc = mdex_addfile(ddex, dst, q, mflags); if (rc) { err = errno; goto err_ddex_free; } rc = syncdirlocal(sdex, ddex, src, dst, sdex->basedirlen - sdex->rootdirlen, q, stats, opt, flags); err_ddex_free: mdex_free(ddex); err_sdex_free: mdex_free(sdex); if (err) errno = err; return rc; } static char *mkfilename(const char *dir, const char *file) { char *filename; int rc; rc = snprintf(NULL, 0, "%s/%s", dir, file) + 1; filename = malloc(rc); if (!filename) return NULL; snprintf(filename, rc, "%s/%s", dir, file); return filename; } int lc_syncfilelocal(const char *dst, char *src, q_t *q, lc_stat_t *stats, lc_sync_options_t *opt, int flags) { (void)stats, (void)opt, (void)flags; /* unused */ struct stat sbs = {0}, sbd = {0}; char *smap, *dmap, *fname = NULL; const char *ddst = dst; size_t sz = 0; int rc = -1, err = 0; /* process and strip trailing slash */ sz = strlen(src); if (!sz) return (errno = EINVAL), -1; sz--; /* no trailing slash => create subdirectory */ if (src[sz] != '/') flags |= SYNC_SUBDIR; else src[sz] = '\0'; /* trim slash */ sz = 0; smap = lc_mmapfile(src, &sz, PROT_READ, MAP_PRIVATE, 0, &sbs); if (smap == MAP_FAILED) { switch (errno) { case EISDIR: return syncrecursive_local(dst, src, q, stats, opt, flags); case ENODATA: rc = creat(ddst, sbs.st_mode & 0777); if (rc != -1) { close(rc); goto err_errno; } /* fallthru */ default: err = errno; goto err_errno; } } sbd.st_mode = sbs.st_mode; sz = sbs.st_size; remap_ddst: dmap = lc_mmapfile(ddst, &sz, PROT_READ|PROT_WRITE, MAP_SHARED, 0, &sbd); if (dmap == MAP_FAILED) { if (errno == EISDIR) { char *tmp = strdup(src); fname = mkfilename(dst, basename(tmp)); free(tmp); ddst = fname; goto remap_ddst; } else { err = errno; goto err_free_smap; } } if (sbs.st_size > sbd.st_size) { /* source is longer, copy extra bytes before syncing first part */ size_t ext = sbs.st_size - sbd.st_size; memcpy(dmap + sbs.st_size - ext, smap + sbs.st_size - ext, ext); if (stats) stats->byt_info += ext; /* Information Rate */ } rc = lc_memsync(dmap, smap, sz, q, stats, opt, flags); msync(dmap, sz, MS_SYNC); /* on OpenBSD an explicit msync() is required */ munmap(dmap, sz); err_free_smap: munmap(smap, sz); err_errno: setfilestat(ddst, &sbs, flags); if (fname) free(fname); if (err) errno = err; return rc; } #ifdef HAVE_RQ_OTI ssize_t lc_sync(lc_ctx_t *lctx, unsigned char *hash, void *data, const size_t len, q_t *q, lc_stat_t *stats, lc_sync_options_t *opt, int flags) { (void)stats, (void)opt, (void)flags; /* unused */ mtree_t stree = {0}; mtree_t dtree = {0}; unsigned char *map; ssize_t byt = 0, rc; if ((rc = lc_recvtree(lctx, hash, &stree, stats, opt, flags)) == -1) return -1; if ((rc = mtree_init(&dtree, len) == -1)) goto err_free_stree; if ((rc = mtree_build(&dtree, data, q) == -1)) goto err_free_dtree; map = mtree_diff_subtree(&stree, &dtree, 0, 1); if (map) { size_t min = mtree_subtree_data_min(stree.base, 0); unsigned char *ptr; for (size_t z = 0; z < stree.chunks; z++) { if (isset(map, z)) { size_t off = z * MTREE_CHUNKSIZE; size_t sz = MIN(MTREE_CHUNKSIZE, len - off); ptr = (unsigned char *)data + off; unsigned char *chunkhash = mtree_nnode(&stree, min + z); rc = lc_recvchunk(lctx, chunkhash, ptr, sz, stats, opt, flags); if (rc == -1) break; byt += rc; } } free(map); if (rc != -1) rc = byt; } err_free_dtree: mtree_free(&dtree); err_free_stree: mtree_free(&stree); return rc; } static void * sync_chunk(void *arg) { struct syncjob *job = (struct syncjob *)arg; unsigned char hash[HASHSIZE]; do { job->rc = lc_recvchunk(job->lctx, job->hash, job->ptr, job->sz, job->stats, NULL, job->flags); hash_generic(hash, sizeof hash, job->ptr, job->sz); } while (memcmp(hash, job->hash, HASHSIZE)); sem_post(&job->done); sem_post(&semjob); return NULL; } inline static ssize_t syncfile(lc_ctx_t *lctx, unsigned char *map, mtree_t *stree, char **dst, size_t len, q_t *q, lc_stat_t *stats, lc_sync_options_t *opt, int flags) { (void)opt; /* unused */ struct syncjob *job; ssize_t byt = 0, rc = 0; size_t min = mtree_subtree_data_min(stree->base, 0); int diffs = hamm(map, stree->chunks); int err = 0, j = 0; job = calloc(diffs, sizeof(struct syncjob)); if (!job) return -1; /* queue jobs to sync each differing chunk */ sem_init(&semjob, 0, SYNC_MAX_RECVERS); for (size_t z = 0; z < stree->chunks; z++) { if (isset(map, z)) { sem_wait(&semjob); size_t off = z * MTREE_CHUNKSIZE; job[j].lctx = lctx; job[j].sz = MIN(MTREE_CHUNKSIZE, len - off); job[j].ptr = (unsigned char *)dst + off; job[j].hash = mtree_nnode(stree, min + z); job[j].stats = stats; job[j].flags = flags; sem_init(&job[j].done, 0, 0); q_push(q, sync_chunk, &job[j++]); } } /* reap jobs, gather stats */ for (int i = 0; i < diffs; i++) { sem_wait(&job[i].done); sem_destroy(&job[i].done); if (job[i].rc > 0) { /* Gross rate set by lc_recvtree & lc_recvchunk */ if (stats) stats->byt_info += job[i].sz; /* Information Rate */ byt += job[i].sz; } else { rc = -1; err = job->err; } } sem_destroy(&semjob); if (rc != -1) rc = byt; else err = errno; free(job); if (err) errno = err; return rc; } static char *mkentryname(const char *pathname, net_tree_t *data, size_t trim) { char *name = NULL; int rc; if (trim >= data->namesz) return NULL; rc = snprintf(NULL, 0, "%s/%.*s", pathname, (int)(data->namesz - trim), data->tree + trim); name = malloc(rc + 1); if (!name) return NULL; snprintf(name, rc + 1, "%s/%.*s", pathname, (int)(data->namesz - trim), data->tree + trim); return name; } static char *mksubdir(lc_ctx_t *lctx, const char *pathname, net_tree_t *data, size_t trim) { char *subdir = NULL; int rc; subdir = mkentryname(pathname, data, trim); if (!subdir) return NULL; rc = mkdir(subdir, 0755); /* create writable, will set mode later */ if (rc == -1) goto err_free_subdir; DEBUG_SYNC("%s\n", subdir); return subdir; err_free_subdir: rc = errno; free(subdir); errno = rc; return NULL; } static ssize_t synclink(lc_ctx_t *lctx, const char *pathname, net_tree_t *data, int flags, size_t trim, int level) { const char *linkpath; char *lpath = NULL; char *target; char *ptr; size_t targetsz = data->size - data->namesz - sizeof(net_tree_t); int rc; if (level && flags & SYNC_SUBDIR) { if (data->namesz) { lpath = mkentryname(pathname, data, trim); if (!lpath) return -1; linkpath = lpath; } else return (errno = EBADMSG), -1; } else linkpath = pathname; ptr = (char *)(data->tree + data->namesz); target = strndup(ptr, targetsz); rc = symlink(target, linkpath); if (rc == -1) { if (errno == EEXIST) rc = 0; } else DEBUG_SYNC("%s\n", linkpath); /* XXX: do not set mode for symlinks */ if (!rc) setfilemeta(linkpath, data, (flags | SYNC_MODE) ^ SYNC_MODE); free(target); free(lpath); return rc; } static ssize_t syncdir(lc_ctx_t *lctx, mdex_t *ddex, const char *pathname, net_tree_t *data, q_t *q, lc_stat_t *stats, lc_sync_options_t *opt, int flags, size_t trim) { ssize_t byt = 0; ssize_t rc = 0; char *subdir = NULL; if (!data->namesz) return -1; if (flags & SYNC_SUBDIR) subdir = mksubdir(lctx, pathname, data, trim); else flags |= SYNC_SUBDIR; if (flags & SYNC_RECURSE) { unsigned char *hash = data->tree + data->namesz; int entries = (data->size - data->namesz - sizeof(net_tree_t)) / HASHSIZE; for (int i = 0; i < entries; i++) { if (mdex_get(ddex, hash, HASHSIZE, NULL)) { rc = lc_syncfile(lctx, hash, pathname, q, stats, opt, flags); if (rc == -1) break; } byt += rc; hash += HASHSIZE; } } if (subdir) { setfilemeta(subdir, data, flags); free(subdir); } else setfilemeta(pathname, data, flags); return (rc == -1) ? -1 : byt; } static mdex_t *index_dest(lc_ctx_t *lctx, const char *pathname, net_tree_t *data, q_t *q, int trim) { mdex_t *ddex; char *subdir; int rc; ddex = mdex_init(0); if (!ddex) return NULL; subdir = mkentryname(pathname, data, trim); DEBUG_SYNC("hashing directory %s... ", subdir); rc = mdex_addfile(ddex, subdir, q, MDEX_RECURSE); if (rc == -1) goto err_free_subdir; DEBUG_SYNC("done.\n"); free(subdir); return ddex; err_free_subdir: rc = errno; free(subdir); errno = rc; mdex_free(ddex); return NULL; } ssize_t lc_syncfile(lc_ctx_t *lctx, unsigned char *hash, const char *pathname, q_t *q, lc_stat_t *stats, lc_sync_options_t *opt, int flags) { mtree_t stree = {0}, dtree = {0}; static mdex_t *ddex; /* destination mdex */ struct stat sbd = {0}; char **dst = NULL; char *fname = NULL; const char *mapfile = pathname; unsigned char *map; pthread_t *tid; ssize_t byt = 0, rc; size_t len = 0; int err = 0, qfree = 0, nthreads; static size_t trim; static int level; net_tree_t *data = NULL; if ((rc = lc_recvnettree(lctx, hash, &data, stats, opt, flags)) == -1) return -1; byt += rc; if ((size_t)rc < sizeof(struct net_tree_s)) err = ENOMSG; else switch (data->mode & S_IFMT) { case S_IFDIR: if (!(flags & SYNC_SUBDIR)) { trim = ((opt && opt->sharelen) ? opt->sharelen : data->namesz) + 1; } else if (opt) trim = opt->trim; if (!level && (flags & SYNC_RECURSE)) { ddex = index_dest(lctx, pathname, data, q, trim); } level++; rc = syncdir(lctx, ddex, pathname, data, q, stats, opt, flags, trim); level--; goto err_return; case S_IFLNK: rc = synclink(lctx, pathname, data, flags, trim, level); goto err_return; case S_IFREG: default: if (buildtree(rc, lctx, &stree, data) == -1) err = ENOMSG; } if (err) goto err_return; nthreads = MIN(MTREE_THREADMAX, stree.base); tid = calloc(nthreads, sizeof(pthread_t)); if (!tid) { err = errno; rc = -1; goto err_free_stree; } if (!q) { /* no queue supplied, allocate one */ if (!(q = calloc(1, sizeof *q))) { err = errno; goto err_free_tid; } qfree |= 1; if (q_init(q) == -1) { err = errno; goto err_free_q; } qfree |= 2; if (q_pool_create(tid, nthreads, q_job_seek, q) != 0) { err = errno; goto err_free_q; } qfree |= 4; } len = stree.len; if (level && flags & SYNC_SUBDIR) { if (data->namesz) { fname = mkentryname(pathname, data, trim); if (!fname) goto err_free_q; mapfile = fname; } else { errno = EBADMSG, rc = -1; goto err_free_q; } } DEBUG_SYNC("%s\n", mapfile); if (!len) { /* zero-length file */ rc = creat(mapfile, 0755); if (rc == -1) { errno = err; goto err_free_q; } close(rc); goto do_setfilemeta; } dst = lc_mmapfile(mapfile, &len, PROT_READ|PROT_WRITE, MAP_SHARED, 0, &sbd); if (dst == MAP_FAILED) { err = errno; rc = -1; goto err_free_q; } if (mtree_init(&dtree, len) == -1) { err = errno; rc = -1; goto err_free_dst; } if (mtree_build(&dtree, dst, q) == -1) { err = errno; rc = -1; goto err_free_dtree; } map = mtree_diff_subtree(&stree, &dtree, 0, 1); if (map) { rc = syncfile(lctx, map, &stree, dst, len, q, stats, opt, 0); if (rc != -1) { rc = byt; } else err = errno; msync(dst, len, MS_SYNC); /* on OpenBSD an explicit msync() is required */ free(map); } /* Clean up. My goodness we've made such an awful mess. Sorry Mum! */ err_free_dtree: mtree_free(&dtree); err_free_dst: munmap(dst, len); do_setfilemeta: if (rc != -1 && data) setfilemeta(mapfile, data, flags); err_free_q: free(fname); if (qfree) { if (qfree & 4) q_pool_destroy(tid, nthreads); if (qfree & 2) q_free(q); if (qfree & 1) free(q); } err_free_tid: free(tid); err_free_stree: mtree_free(&stree); err_return: if (err) errno = err; free(data); if (!level && ddex) mdex_free(ddex); return (rc == -1) ? -1 : byt; } /* process trailing slash and hash src before calling lc_syncfile */ ssize_t lc_syncfile_hash(lc_ctx_t *lctx, char *src, const char *dst, q_t *q, lc_stat_t *stats, lc_sync_options_t *opt, int flags) { unsigned char hash[HASHSIZE]; size_t len = strlen(src); ssize_t rc = -1; int optalloc = 0; if (!len) return (errno = EINVAL), -1; if (!opt) { opt = calloc(1, sizeof(lc_sync_options_t)); optalloc++; } if (!opt) return -1; if (src[len - 1] != '/') { /* no trailing slash => create subdirectory */ flags |= SYNC_SUBDIR; char *tmp = strdup(src); if (!tmp) goto err_free_opt; opt->trim = strlen(basename(tmp)); free(tmp); } else { src[--len] = '\0'; /* trim slash */ opt->trim = -1; } hash_generic(hash, sizeof hash, (unsigned char *)src, len); opt->share = src; opt->sharelen = strlen(opt->share); opt->trim = opt->sharelen - opt->trim; rc = lc_syncfile(lctx, hash, dst, q, stats, opt, flags); err_free_opt: if (optalloc) free(opt); return rc; } #endif /* HAVE_LIBLCRQ */ librecast/test/000077500000000000000000000000001502456746400140225ustar00rootroot00000000000000librecast/test/.gitignore000066400000000000000000000001261502456746400160110ustar00rootroot00000000000000*.log *.valgrind ????-????.tmp.?????? ????-????.???.tmp.?????? testlog-?????? lastlog librecast/test/0000-0000.c000066400000000000000000000006751502456746400151320ustar00rootroot00000000000000#include "test.h" #include "falloc.h" #include int main(void) { lc_ctx_t * lctx; test_name("lc_ctx_new() / lc_ctx_free()"); lctx = lc_ctx_new(); lc_ctx_free(lctx); if (RUNNING_ON_VALGRIND) return test_status; /* force ENOMEM */ falloc_setfail(0); lctx = lc_ctx_new(); test_assert(errno == ENOMEM, "lc_ctx_new() - ENOMEM"); test_assert(lctx == NULL, "lc_ctx_new() - ENOMEM, return NULL"); return test_status; } librecast/test/0000-0001.c000066400000000000000000000031551502456746400151270ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2017-2023 Brett Sheffield */ /* * testing lc_socket_new() / lc_socket_close() * test is intended to be run under valgrind (`make memcheck/0001`) to check for * leaks */ #include "test.h" #include "falloc.h" #include int main(void) { lc_ctx_t *lctx; lc_socket_t *sock, *sock2; test_name("lc_socket_new() / lc_socket_close()"); lctx = lc_ctx_new(); if (!test_assert(lctx != NULL, "lc_ctx_new()")) return test_status; sock = lc_socket_new(lctx); if (!test_assert(sock != NULL, "lc_socket_new()")) goto err_ctx_free; lc_socket_close(sock); lc_ctx_free(lctx); /* lc_ctx_free() should clean up socket without needing explicit lc_socket_close() */ lctx = lc_ctx_new(); if (!test_assert(lctx != NULL, "lc_ctx_new()")) return test_status; sock = lc_socket_new(lctx); if (!test_assert(sock != NULL, "sock allocated")) goto err_ctx_free; sock2 = lc_socket_new(lctx); (void) sock2; /* "use" variable to keep compiler happy */ if (!test_assert(sock != NULL, "sock2 allocated")) goto err_ctx_free; lc_ctx_free(lctx); /* Say bye to valgrind - it finds the things that happen next upsetting */ if (RUNNING_ON_VALGRIND) return test_status; /* force ENOMEM */ lctx = lc_ctx_new(); if (!test_assert(lctx != NULL, "lc_ctx_new()")) return test_status; falloc_setfail(1); sock = lc_socket_new(lctx); /* will fail with ENOMEM */ test_assert(errno == ENOMEM, "lc_socket_new() - ENOMEM"); test_assert(sock == NULL, "lc_socket_new() - ENOMEM, return NULL"); err_ctx_free: lc_ctx_free(lctx); return test_status; } librecast/test/0000-0002.c000066400000000000000000000021111502456746400151170ustar00rootroot00000000000000#include "test.h" #include "falloc.h" #include int main(void) { lc_ctx_t *lctx; lc_channel_t *chan; test_name("lc_channel_new() / lc_channel_free()"); lctx = lc_ctx_new(); chan = lc_channel_new(lctx, "example.com"); test_assert(chan != NULL, "lc_channel_new() - channel allocated (1)"); lc_channel_free(chan); lc_ctx_free(lctx); /* lc_ctx_free() should clean up channel without needing explicit lc_channel_free() */ lctx = lc_ctx_new(); chan = lc_channel_new(lctx, "clean exit"); test_assert(chan != NULL, "lc_channel_new() - channel allocated (2)"); lc_ctx_free(lctx); if (RUNNING_ON_VALGRIND) return test_status; /* force ENOMEM */ lctx = lc_ctx_new(); falloc_setfail(0); chan = lc_channel_init(lctx, NULL); test_assert(errno == ENOMEM, "lc_channel_new() - ENOMEM"); test_assert(chan == NULL, "lc_channel_new() - ENOMEM, return NULL"); chan = lc_channel_nnew(lctx, NULL, 0); test_assert(errno == ENOMEM, "lc_channel_new() - ENOMEM"); test_assert(chan == NULL, "lc_channel_new() - ENOMEM, return NULL"); lc_ctx_free(lctx); return test_status; } librecast/test/0000-0003.c000066400000000000000000000002351502456746400151250ustar00rootroot00000000000000#include "test.h" #include int main(void) { lc_message_t msg; test_name("lc_msg_init()"); lc_msg_init(&msg); return test_status; } librecast/test/0000-0004.c000066400000000000000000000010121502456746400151200ustar00rootroot00000000000000#include "test.h" #include "falloc.h" #include int main(void) { lc_message_t msg; test_name("lc_msg_init_size() / lc_msg_free()"); test_assert(!lc_msg_init_size(&msg, 1024), "lc_msg_init_size()"); lc_msg_free(&msg); if (RUNNING_ON_VALGRIND) return test_status; /* force ENOMEM */ falloc_setfail(0); test_assert(lc_msg_init_size(&msg, 1024) == -1, "lc_msg_init_size() - return -1 on ENOMEM"); test_assert(errno == ENOMEM, "lc_msg_init_size() - errno set to ENOMEM"); return test_status; } librecast/test/0000-0005.c000066400000000000000000000015111502456746400151250ustar00rootroot00000000000000#include "test.h" #include static int freed; static void *dataptr, *hintptr; void *freeme(void *data, void *hint) { test_log("%p == %p\n", data, dataptr); test_assert(data == dataptr, "msg free called with msg ptr (%zd)", (char *)data-(char *)dataptr ); test_assert(hint == hintptr, "msg free called with hint (%zd)", (char *)hint-(char *)hintptr ); freed++; return NULL; } int main(void) { lc_message_t msg; char data[] = "some data"; size_t len = strlen(data) + 1; test_name("lc_msg_init_data()"); lc_msg_init_data(&msg, data, len, &freeme, &msg); test_assert(msg.data == data, "msg.data points to our buffer"); test_assert(msg.len == len, "msg.len set"); dataptr = msg.data; hintptr = &msg; lc_msg_free(&msg); test_assert(freed == 1, "message free function called"); return test_status; } librecast/test/0000-0006.c000066400000000000000000000071621502456746400151360ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2024-2025 Brett Sheffield */ /* * testing lc_socketpair() - create a pair of connected sockets * then test with various API calls that use sockets */ #include "test.h" #include #include #define CHANNELS 4 int main(void) { lc_ctx_t *lctx; lc_socket_t *sock[2]; lc_channel_t *chan[CHANNELS]; test_name("lc_socketpair()"); lctx = lc_ctx_new(); if (!test_assert(lctx != NULL, "lc_ctx_new()")) return test_status; if (!test_assert(lc_socketpair(lctx, sock) == 0, "lc_socketpair()")) goto err_free_lctx; for (int i = 0; i < 2; i++) { test_assert(sock[i]->type == LC_SOCK_PAIR, "type[%i] == LC_SOCK_PAIR", i); test_assert(lc_socket_raw(sock[i]) != -1, "lc_socket_raw() socket != -1"); } char msg[] = "hello"; char buf[sizeof msg]; ssize_t rc; rc = send(sock[0]->sock, msg, sizeof msg, 0); test_assert(rc == sizeof msg, "%zi bytes sent", rc); rc = recv(sock[1]->sock, buf, sizeof buf, 0); test_assert(rc == sizeof msg, "%zi bytes received", rc); for (int i = 0; i < CHANNELS; i++) { chan[i] = lc_channel_random(lctx); if (!chan[i] || lc_channel_bind(sock[0], chan[i])) goto err_free_lctx; test_assert(lc_channel_socket(chan[i]) == sock[0], "socket %i bound", i); } /* join channels (except last), adding them to the OIL filter */ /* NB: with a socketpair, the OIL for sock->pair is updated, * not the sock itself */ test_assert(sock[1]->oil == NULL, "OIL filter is NULL"); for (int i = 0; i < CHANNELS - 1; i++) { if (!test_assert(lc_channel_join(chan[i]) == 0, "lc_channel_join()[%i]", i)) goto err_free_lctx; } test_assert(sock[1]->oil != NULL, "OIL filter is allocated"); for (int i = 0; i < CHANNELS - 1; i++) { test_assert(lc_socket_oil_cmp(sock[1], chan[i]->hash) == 0, "lc_socket_oil_cmp()[%i]", i); } /* this last group was not added, ensure not found */ test_assert(lc_socket_oil_cmp(sock[1], chan[CHANNELS - 1]->hash) == -1, "lc_socket_oil_cmp() - check for hash not in filter"); test_assert(errno == ENOENT, "ENOENT"); test_assert(lc_socket_ttl(sock[0], 42) == 0, "lc_socket_ttl() returns -1 for socketpair"); test_assert(sock[0]->ttl == 42, "TTL set"); errno = 0; test_assert(lc_socket_loop(sock[0], 1) == -1, "lc_socket_loop() returns -1 for socketpair"); test_assert(errno == ENOTSUP, "lc_socket_loop() => errno == ENOTSUP"); socklen_t optlen; int opt = 1; errno = 0; test_assert(lc_socket_getopt(sock[0], IPV6_MULTICAST_LOOP, &opt, &optlen) == -1, "lc_socket_getopt() returns -1 for socketpair"); test_assert(errno == ENOTSUP, "lc_socket_getopt() => errno == ENOTSUP"); errno = 0; test_assert(lc_socket_setopt(sock[0], IPV6_MULTICAST_LOOP, &opt, sizeof opt) == -1, "lc_socket_setopt() returns -1 for socketpair"); test_assert(errno == ENOTSUP, "lc_socket_setopt() => errno == ENOTSUP"); /* send without joining channel, 0 bytes sent */ rc = lc_channel_send(chan[0], msg, sizeof msg, 0); test_assert(rc == 0, "%zi bytes sent (should be zero)", rc); /* now bind and join the channel and send/recv * NB: chan[0] is bound to sock[0], so a JOIN will get added to the * OIL of sock[1], NOT sock[0] * The easiest way to deal with this for the test is just call * lc_socket_oil_add() */ lc_socket_oil_add(sock[0], chan[0]->hash); rc = lc_channel_send(chan[0], msg, sizeof msg, 0); if (!test_assert((size_t)rc == sizeof msg, "%zi bytes sent", rc)) goto err_free_lctx; rc = lc_socket_recv(sock[1], buf, sizeof buf, 0); test_assert(rc == sizeof msg, "%zi/%zu bytes received", rc, sizeof msg); err_free_lctx: lc_ctx_free(lctx); return test_status; } librecast/test/0000-0007.c000066400000000000000000000041301502456746400151270ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2024-2025 Brett Sheffield */ /* * testing lc_socketpair() - encryption tests */ #include "test.h" #include #include int main(void) { char name[] = "lc_socketpair() - symmetric encryption"; #ifdef HAVE_LIBSODIUM lc_ctx_t *lctx; lc_socket_t *sock[2]; lc_channel_t *chan[2]; unsigned char key[crypto_secretbox_KEYBYTES]; char msg[1024]; char buf[sizeof msg]; ssize_t rc; test_name(name); lctx = lc_ctx_new(); if (!test_assert(lctx != NULL, "lc_ctx_new()")) return test_status; /* generate and set key */ lc_getrandom(key, sizeof key); if (!test_assert(lc_ctx_set_sym_key(lctx, key, sizeof key) == 0, "lc_ctx_set_sym_key()")) goto err_free_lctx; /* turn on encoding */ if (!test_assert(lc_ctx_coding_set(lctx, LC_CODE_SYMM) == LC_CODE_SYMM, "lc_ctx_coding_set()")) goto err_free_lctx; /* create socketpair */ if (!test_assert(lc_socketpair(lctx, sock) == 0, "lc_socketpair()")) goto err_free_lctx; /* create random data to send */ lc_getrandom(msg, sizeof msg); chan[0] = lc_channel_random(lctx); if (!test_assert(chan[0] != NULL, "lc_channel_random()")) goto err_free_lctx; chan[1]= lc_channel_copy(lctx, chan[0]); if (!test_assert(chan[1] != NULL, "lc_channel_copy()")) goto err_free_lctx; if (!test_assert(lc_channel_bind(sock[0], chan[0]) == 0, "lc_channel_bind()")) goto err_free_lctx; if (!test_assert(lc_channel_bind(sock[1], chan[1]) == 0, "lc_channel_bind()")) goto err_free_lctx; /* JOIN channel - ensure channel is in OIL filter */ lc_channel_join(chan[1]); rc = lc_channel_send(chan[0], msg, sizeof msg, 0); test_assert((size_t)rc == sizeof msg, "%zi (total) bytes sent", rc); rc = lc_channel_recv(chan[1], buf, sizeof buf, 0); if (rc) perror("lc_channel_recv"); test_assert(rc == sizeof msg, "%zi (information) bytes decoded", rc); test_assert(!memcmp(msg, buf, sizeof msg), "msg received matches"); err_free_lctx: lc_ctx_free(lctx); return test_status; #else return test_skip("%s - requires libsodium", name); #endif } librecast/test/0000-0008.c000066400000000000000000000115551502456746400151410ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2017-2024 Brett Sheffield */ #include "testnet.h" #include #include #include #include #include #include #include #include #include #undef TESTDEBUG #ifdef TESTDEBUG # define PKTS 10 # define PKTSZ 4 #else # define PKTS 20 # define PKTSZ 1024 #endif #define WAITS 20 #ifdef HAVE_LIBSODIUM #ifdef HAVE_LIBLCRQ enum { TID_SEND, TID_RECV }; static const size_t SZ = PKTS * PKTSZ + 5; static char channel_name[] = "0000-0008"; static lc_ctx_t *lctx; static lc_socket_t *sock[2]; static sem_t receiver_ready, timeout; static unsigned char key[crypto_secretbox_KEYBYTES]; #ifdef TESTDEBUG #if 0 static void dumppkt(uint8_t *pkt, int haseq) { uint16_t seq; uint8_t *dat = pkt; if (haseq) { dat += sizeof seq; seq = ntohs(*(uint16_t *)pkt); fprintf(stderr, "%u: ", seq); } else fprintf(stderr, " "); for (size_t z = 0; z < PKTSZ * 8; z++) { if (isset(dat, z)) putc('1', stderr); else putc('0', stderr); } putc('\n', stderr); } #endif static void dump_bufs(uint8_t buf[2][SZ]) { for (size_t p = 0; p < PKTS; p++) { fprintf(stderr, "%zu: ", p); for (int i = 0; i < 2; i++) { for (size_t z = 0; z < PKTSZ * 8; z++) { uint8_t *b = buf[i]; if (isset(b, p * PKTSZ * 8 + z)) putc('1', stderr); else putc('0', stderr); } putc(' ', stderr); } putc('\n', stderr); } putc('\n', stderr); } #endif static void generate_source_data(uint8_t *buf, size_t sz) { ssize_t rc; int f; f = open("/dev/urandom", O_RDONLY); if (f == -1) return; rc = read(f, buf, sz); test_assert(rc == (ssize_t)sz, "%zi random bytes read", rc); close(f); } static void *recv_data_fec(void *arg) { uint8_t *buf = (uint8_t *)arg; ssize_t rc; lc_channel_t * chan = lc_channel_new(lctx, channel_name); memset(buf, 0, SZ); /* clear receive buffer */ lc_channel_bind(sock[1], chan); lc_socket_oil_add(sock[0], lc_channel_get_hash(chan)); sem_post(&receiver_ready); rc = lc_channel_recv(chan, buf, SZ, 0); if (rc == -1) perror("lc_channel_recv"); test_log("lc_channel_recv returned %zi\n", rc); test_assert(rc >= (ssize_t)SZ, "data received %zi/%zu bytes", rc, SZ); lc_channel_part(chan); sem_post(&timeout); return arg; } static void *send_data_fec(void *arg) { uint8_t *buf = (uint8_t *)arg; lc_channel_t * chan = lc_channel_new(lctx, channel_name); rq_t *rq; ssize_t rc; size_t byt = 0; lc_channel_bind(sock[0], chan); test_log("sending data with FEC + symmetric encryption\n"); sem_wait(&receiver_ready); rc = lc_channel_send(chan, buf, SZ, 0); if (rc == -1) perror("lc_channel_send"); if (!test_assert(rc != -1, "lc_channel_send encoded data, returned %zi", rc)) return NULL; byt = rc; rq = lc_channel_rq(chan); /* Send packets. Drop packet 3 */ int pkts = rq_KP(rq) + RQ_OVERHEAD * 2; test_log("sending %u packets\n", pkts); for (int i = 1; i < pkts; i++) { int flags = (i == 3) ? MSG_DROP : 0; rc = lc_channel_send(chan, NULL, 0, flags); if (rc == -1) perror("lc_channel_send"); test_assert(rc >= 0, "lc_channel_send encoded data, returned %zi", rc); if (rc > 0) byt += rc; } test_assert(byt >= SZ, "data sent %zi bytes (buffer = %zu)", byt, SZ); return arg; } #endif #endif int main(void) { #if !defined(HAVE_LIBLCRQ) || !(HAVE_LIBSODIUM) return test_skip("lc_channel_send() / lc_socket_recv() - FEC + encrypt"); #else pthread_t tid[2]; uint8_t buf[2][SZ]; struct timespec ts; test_name("lc_channel_send() / lc_socket_recv() - FEC + encrypt (socketpair)"); test_require_net(TEST_NET_BASIC); lctx = lc_ctx_new(); if (!test_assert(lctx != NULL, "lc_ctx_new()")) return test_status; /* generate symmetric encryption key */ crypto_secretbox_keygen(key); lc_ctx_set_sym_key(lctx, key, crypto_secretbox_KEYBYTES); lc_ctx_coding_set(lctx, LC_CODE_SYMM | LC_CODE_FEC_RQ); if (!test_assert(lc_socketpair(lctx, sock) == 0, "lc_socketpair()")) goto err_free_lctx; /* clear buffers */ memset(buf[0], 0, SZ); memset(buf[1], 0, SZ); sem_init(&timeout, 0, 0); sem_init(&receiver_ready, 0, 0); generate_source_data(buf[TID_SEND], SZ); test_assert(memcmp(buf[TID_RECV], buf[TID_SEND], SZ), "buffer differ before sync"); pthread_create(&tid[TID_SEND], NULL, &send_data_fec, buf[TID_SEND]); pthread_create(&tid[TID_RECV], NULL, &recv_data_fec, buf[TID_RECV]); clock_gettime(CLOCK_REALTIME, &ts); ts.tv_sec += WAITS; test_assert(!sem_timedwait(&timeout, &ts), "timeout"); pthread_cancel(tid[TID_RECV]); pthread_join(tid[TID_RECV], NULL); pthread_cancel(tid[TID_SEND]); pthread_join(tid[TID_SEND], NULL); sem_destroy(&receiver_ready); sem_destroy(&timeout); test_assert(!memcmp(buf[TID_RECV], buf[TID_SEND], SZ), "send buffer matches received"); #ifdef TESTDEBUG dump_bufs(buf); #endif err_free_lctx: lc_ctx_free(lctx); return test_status; #endif } librecast/test/0000-0009.c000066400000000000000000000021501502456746400151310ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2017-2023 Brett Sheffield */ /* testing lc_channel_bind() / lc_channel_unbind() */ #include "test.h" #include int main(void) { lc_ctx_t *lctx = NULL; lc_socket_t *sock = NULL; lc_channel_t *chan = NULL; test_name("lc_channel_bind() / lc_channel_unbind()"); lctx = lc_ctx_new(); if (!test_assert(lctx != NULL, "lc_ctx_new()")) return test_status; sock = lc_socket_new(lctx); if (!test_assert(sock != NULL, "lc_socket_new()")) goto err_ctx_free; chan = lc_channel_new(lctx, "example.com"); if (!test_assert(chan != NULL, "lc_channel_new()")) goto err_ctx_free; test_assert(lc_channel_bind(sock, chan) == 0, "lc_channel_bind returns 0 on success"); test_assert(lc_channel_socket(chan) == sock, "lc_channel_bind() binds channel to socket"); test_assert(lc_channel_unbind(chan) == 0, "lc_channel_unbind() returns 0 on success"); test_assert(lc_channel_socket(chan) == NULL, "lc_channel_unbind() sets chan->socket to NULL"); err_ctx_free: lc_ctx_free(lctx); return test_status; } librecast/test/0000-0010.c000066400000000000000000000015721502456746400151300ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2020-2024 Brett Sheffield */ #include "testnet.h" #include int main(void) { lc_ctx_t *lctx = NULL; lc_socket_t *sock = NULL; lc_channel_t *chan = NULL; test_name("lc_channel_join() / lc_channel_part()"); test_require_net(TEST_NET_BASIC); lctx = lc_ctx_new(); sock = lc_socket_new(lctx); chan = lc_channel_new(lctx, "example.com"); if (!test_assert(lc_channel_bind(sock, chan) == 0, "lc_channel_bind()")) goto err_free_chan; test_assert(lc_channel_join(chan) == 0, "lc_channel_join() returns 0 on success"); /* TODO: test failure (remove all interfaces) */ test_assert(lc_channel_part(chan) == 0, "lc_channel_part() returns 0 on success"); err_free_chan: lc_channel_free(chan); lc_socket_close(sock); lc_ctx_free(lctx); return test_status; } librecast/test/0000-0011.c000066400000000000000000000031511502456746400151240ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2017-2023 Brett Sheffield */ /* testing lc_socket_listen() / lc_socket_listen_cancel() */ #include "test.h" #include "testnet.h" #include int main(void) { lc_ctx_t *lctx = NULL; lc_socket_t *sock = NULL; lc_channel_t *chan = NULL; int rc = 0; test_name("lc_socket_listen() / lc_socket_listen_cancel()"); test_require_net(TEST_NET_BASIC); lctx = lc_ctx_new(); if (!test_assert(lctx != NULL, "lc_ctx_new()")) return test_status; sock = lc_socket_new(lctx); if (!test_assert(sock != NULL, "lc_socket_new()")) goto err_ctx_free; chan = lc_channel_new(lctx, "example.com"); if (!test_assert(chan != NULL, "lc_channel_new()")) goto err_ctx_free; rc = lc_channel_bind(sock, chan); if (!test_assert(rc == 0, "lc_channel_bind()")) goto err_ctx_free; rc = lc_channel_join(chan); if (!test_assert(rc == 0, "lc_channel_join()")) goto err_ctx_free; test_assert(lc_socket_listen(NULL, NULL, NULL) == LC_ERROR_SOCKET_REQUIRED, "lc_socket_listen requires socket"); test_assert(lc_socket_listen(sock, NULL, NULL) == 0, "lc_socket_listen() returns 0 on success"); test_assert(lc_socket_listen(sock, NULL, NULL) == LC_ERROR_SOCKET_LISTENING, "lc_socket_listen() returns LC_ERROR_SOCKET_LISTENING when socket busy"); test_assert(lc_socket_listen_cancel(sock) == 0, "lc_socket_listen_cancel() returns 0 on success"); test_assert(lc_socket_listen_cancel(sock) == 0, "lc_socket_listen_cancel() can be called twice"); err_ctx_free: if (rc) perror("error"); lc_ctx_free(lctx); return test_status; } librecast/test/0000-0012.c000066400000000000000000000032201502456746400151220ustar00rootroot00000000000000#include "testnet.h" #include #include #include #include #include #define WAITS 1 static sem_t timeout; void msg_received(lc_message_t *msg) { (void)msg; test_log("message received\n"); sem_post(&timeout); } int main(void) { lc_ctx_t *lctx; lc_socket_t *sock; lc_channel_t *chan; lc_message_t msg; ssize_t byt; struct timespec ts; int op = LC_OP_PING; int opt = 1; test_name("multicast ping (loopback)"); test_require_net(TEST_NET_BASIC); lctx = lc_ctx_new(); test_assert(lctx != NULL, "lctx != NULL"); sock = lc_socket_new(lctx); test_assert(sock != NULL, "sock != NULL"); chan = lc_channel_new(lctx, "example.com"); test_assert(chan != NULL, "chan != NULL"); test_assert(!lc_socket_setopt(sock, IPV6_MULTICAST_LOOP, &opt, sizeof(opt)), "set IPV6_MULTICAST_LOOP"); test_assert(!lc_channel_bind(sock, chan), "lc_channel_bind()"); test_assert(!lc_channel_join(chan), "lc_channel_join()"); test_assert(!lc_socket_listen(sock, &msg_received, NULL), "lc_socket_listen()"); /* send packet and receive on loopback */ lc_msg_init(&msg); lc_msg_set(&msg, LC_ATTR_OPCODE, &op); byt = lc_msg_send(chan, &msg); test_assert((size_t)byt == msg.len + sizeof(lc_message_head_t), "%zi bytes sent", byt); if (byt == -1) { perror("lc_msg_send"); } sem_init(&timeout, 0, 0); clock_gettime(CLOCK_REALTIME, &ts); ts.tv_sec += WAITS; test_assert(!sem_timedwait(&timeout, &ts), "timeout"); sem_destroy(&timeout); test_assert(!lc_socket_listen_cancel(sock), "lc_socket_listen_cancel()"); lc_channel_free(chan); lc_socket_close(sock); lc_ctx_free(lctx); return test_status; } librecast/test/0000-0013.c000066400000000000000000000035551502456746400151360ustar00rootroot00000000000000#include "testnet.h" #include #include #include #include int gotmsg = 0; void sighandler(int sig) { test_log("caught signal %i\n", sig); } void msg_received(lc_message_t *msg) { (void)msg; test_log("message received\n"); gotmsg = 1; kill(getpid(), SIGINT); } int main(void) { lc_ctx_t *lctx = NULL; lc_socket_t *sock[2] = { NULL, NULL }; lc_channel_t *chan[2] = { NULL, NULL }; lc_message_t msg; test_name("multicast ping (loopback) - don't receive msgs for other channels"); test_require_net(TEST_NET_BASIC); lctx = lc_ctx_new(); sock[0] = lc_socket_new(lctx); sock[1] = lc_socket_new(lctx); chan[0] = lc_channel_new(lctx, "chan0"); chan[1] = lc_channel_new(lctx, "chan1"); test_assert(!lc_channel_bind(sock[0], chan[0]), "lc_channel_bind() 0"); test_assert(!lc_channel_bind(sock[1], chan[1]), "lc_channel_bind() 1"); test_assert(!lc_channel_join(chan[0]), "lc_channel_join() 0"); /* do NOT join channel 1 */ test_assert(!lc_socket_listen(sock[0], msg_received, NULL), "lc_socket_listen() 0"); test_assert(!lc_socket_listen(sock[1], msg_received, NULL), "lc_socket_listen() 1"); /* send packet and receive on loopback */ int op = LC_OP_PING; lc_msg_init(&msg); lc_msg_set(&msg, LC_ATTR_OPCODE, &op); signal(SIGINT, sighandler); lc_msg_send(chan[1], &msg); /* send to channel we are NOT joined to */ struct timespec t; t.tv_sec = 0; t.tv_nsec = 99999999; nanosleep(&t, &t); /* fail if message for wrong channel was received */ test_assert(!gotmsg, "received loopback message on channel not joined"); test_assert(!lc_socket_listen_cancel(sock[0]), "lc_socket_listen_cancel()"); test_assert(!lc_socket_listen_cancel(sock[1]), "lc_socket_listen_cancel()"); lc_channel_free(chan[0]); lc_channel_free(chan[1]); lc_socket_close(sock[0]); lc_socket_close(sock[1]); lc_ctx_free(lctx); return test_status; } librecast/test/0000-0014.c000066400000000000000000000033741502456746400151360ustar00rootroot00000000000000#include "testnet.h" #include #include #include #include #include #include int gotmsg = 0; void sighandler(int sig) { test_log("caught signal %i\n", sig); } void msg_received(lc_message_t *msg) { (void)msg; test_log("message received\n"); gotmsg = 1; kill(getpid(), SIGINT); } int main(void) { lc_ctx_t *lctx = NULL; lc_socket_t *sock = NULL; lc_channel_t *chan = NULL; lc_message_t msg; struct ifaddrs *ifaddr, *ifa; test_name("multicast ping (loopback disabled)"); test_require_net(TEST_NET_BASIC); lctx = lc_ctx_new(); sock = lc_socket_new(lctx); chan = lc_channel_new(lctx, "example.com"); /* find first interface that supports IPv6 multicast */ test_assert(getifaddrs(&ifaddr) != -1, "getifaddrs()"); for (ifa = ifaddr; ifa; ifa = ifa->ifa_next) { if ((ifa->ifa_flags & IFF_MULTICAST) == IFF_MULTICAST && ifa->ifa_addr && ifa->ifa_addr->sa_family == AF_INET6) { lc_socket_bind(sock, if_nametoindex(ifa->ifa_name)); break; } } freeifaddrs(ifaddr); test_assert(!lc_channel_bind(sock, chan), "lc_channel_bind()"); test_assert(!lc_channel_join(chan), "lc_channel_join()"); test_assert(!lc_socket_listen(sock, msg_received, NULL), "lc_socket_listen()"); /* send packet with loopback turned off */ char *data = "BLACK LIVES MATTER"; lc_msg_init_data(&msg, data, strlen(data), NULL, NULL); signal(SIGINT, sighandler); lc_msg_send(chan, &msg); struct timespec t; t.tv_sec = 0; t.tv_nsec = 99999999; nanosleep(&t, &t); test_assert(!gotmsg, "received loopback message when loopback disabled"); test_assert(!lc_socket_listen_cancel(sock), "lc_socket_listen_cancel()"); lc_channel_free(chan); lc_socket_close(sock); lc_ctx_free(lctx); return test_status; } librecast/test/0000-0015.c000066400000000000000000000033211502456746400151270ustar00rootroot00000000000000#include "testnet.h" #include #include #include #define WAITS 1 static char channel_name[] = "0000-0015"; static sem_t sem; static ssize_t bytes = -1; static void *listen_thread(void *arg) { lc_ctx_t * lctx; lc_socket_t * sock; lc_channel_t * chan; lctx = lc_ctx_new(); sock = lc_socket_new(lctx); chan = lc_channel_new(lctx, channel_name); lc_channel_bind(sock, chan); lc_channel_join(chan); sem_post(&sem); /* tell send thread we're ready */ bytes = lc_socket_recv(sock, (char *)arg, BUFSIZ, 0); sem_post(&sem); /* tell send thread we're done */ lc_ctx_free(lctx); return arg; } int main(void) { lc_ctx_t * lctx; lc_socket_t * sock; lc_channel_t * chan; pthread_attr_t attr = {0}; pthread_t thread; struct timespec ts; char buf[] = "liberté"; char recvbuf[BUFSIZ] = ""; size_t len = strlen(buf) + 1; test_name("lc_channel_send() / lc_socket_recv()"); test_require_net(TEST_NET_BASIC); sem_init(&sem, 0, 0); pthread_attr_init(&attr); pthread_create(&thread, &attr, &listen_thread, &recvbuf); pthread_attr_destroy(&attr); sem_wait(&sem); /* recv thread is ready */ lctx = lc_ctx_new(); sock = lc_socket_new(lctx); chan = lc_channel_new(lctx, channel_name); lc_socket_loop(sock, 1); lc_channel_bind(sock, chan); lc_channel_send(chan, buf, len, 0); lc_ctx_free(lctx); test_assert(!clock_gettime(CLOCK_REALTIME, &ts), "clock_gettime()"); ts.tv_sec += WAITS; test_assert(!sem_timedwait(&sem, &ts), "timeout"); sem_timedwait(&sem, &ts); sem_destroy(&sem); pthread_cancel(thread); pthread_join(thread, NULL); test_assert(bytes == (ssize_t)len, "received %zi bytes, expected %zu", bytes, len); test_expect(buf, recvbuf); return test_status; } librecast/test/0000-0016.c000066400000000000000000000037171502456746400151410ustar00rootroot00000000000000#include "testnet.h" #include #include #include #define WAITS 1 static char channel_name[] = "0000-0016"; static sem_t sem; static ssize_t bytes = -1; static void *listen_thread(void *arg) { lc_ctx_t * lctx; lc_socket_t * sock; lc_channel_t * chan; struct iovec iov; struct msghdr msg = {0}; lctx = lc_ctx_new(); sock = lc_socket_new(lctx); chan = lc_channel_new(lctx, channel_name); iov.iov_base = arg; iov.iov_len = BUFSIZ; msg.msg_iov = &iov; msg.msg_iovlen = 1; lc_channel_bind(sock, chan); lc_channel_join(chan); sem_post(&sem); /* tell send thread we're ready */ bytes = lc_socket_recvmsg(sock, &msg, 0); sem_post(&sem); /* tell send thread we're done */ lc_ctx_free(lctx); return arg; } int main(void) { lc_ctx_t * lctx; lc_socket_t * sock; lc_channel_t * chan; pthread_attr_t attr = {0}; pthread_t thread; struct timespec ts; char buf[] = "liberté"; char recvbuf[BUFSIZ] = ""; struct iovec iov; struct msghdr msg = {0}; test_name("lc_channel_sendmsg() / lc_socket_recvmsg()"); test_require_net(TEST_NET_BASIC); sem_init(&sem, 0, 0); pthread_attr_init(&attr); pthread_create(&thread, &attr, &listen_thread, &recvbuf); pthread_attr_destroy(&attr); sem_wait(&sem); /* recv thread is ready */ lctx = lc_ctx_new(); sock = lc_socket_new(lctx); chan = lc_channel_new(lctx, channel_name); iov.iov_base = buf; iov.iov_len = strlen(buf) + 1; msg.msg_iov = &iov; msg.msg_iovlen = 1; lc_socket_loop(sock, 1); lc_channel_bind(sock, chan); lc_channel_sendmsg(chan, &msg, 0); lc_ctx_free(lctx); test_assert(!clock_gettime(CLOCK_REALTIME, &ts), "clock_gettime()"); ts.tv_sec += WAITS; test_assert(!sem_timedwait(&sem, &ts), "timeout"); sem_timedwait(&sem, &ts); sem_destroy(&sem); pthread_cancel(thread); pthread_join(thread, NULL); test_assert(bytes == (ssize_t)iov.iov_len, "received %zi bytes, expected %zu", bytes, iov.iov_len); test_expect(buf, recvbuf); return test_status; } librecast/test/0000-0017.c000066400000000000000000000073751502456746400151460ustar00rootroot00000000000000#include "test.h" #include #include #include #include #include #include #include #include #define WAITS 1 #define IF_COUNT 3 char hail[IF_COUNT][11] = { "Liberté", "Egalité", "Fraternité", }; char recvbuf[IF_COUNT][BUFSIZ] = {0}; static char channel_name[] = "0000-0017"; static char ifname[IF_COUNT][IFNAMSIZ]; static sem_t sem_ready; static sem_t sem_done; static ssize_t bytes = -1; static void *recv_thread(void *arg) { int dir = *(int *)arg; lc_ctx_t * lctx; lc_socket_t * sock; lc_channel_t * chan; test_log("thread %i\n", dir); lctx = lc_ctx_new(); sock = lc_socket_new(lctx); chan = lc_channel_new(lctx, channel_name); test_assert(lc_socket_bind(sock, if_nametoindex(ifname[dir])) == 0, "lc_socket_bind: %s", strerror(errno)); test_log("thread %i bound to interface %s (%u)\n", dir, ifname[dir], if_nametoindex(ifname[dir])); lc_channel_bind(sock, chan); lc_channel_join(chan); test_log("thread %i has raw socket %i\n", dir, lc_socket_raw(sock)); sem_post(&sem_ready); /* tell send thread we're ready */ bytes = lc_socket_recv(sock, recvbuf[dir], BUFSIZ, 0); test_log("thread %i recv'd '%s'\n", dir, recvbuf[dir]); sem_post(&sem_done); /* tell send thread we're done */ lc_ctx_free(lctx); return arg; } static void destroy_interfaces(lc_ctx_t *lctx) { errno = 0; for (int i = 0; i < IF_COUNT; i++) { test_assert(lc_link_set(lctx, ifname[i], LC_IF_DOWN) == 0, "lc_link_set %s DOWN", ifname[i]); perror("lc_link_set"); } } static void disable_dad(char *ifname) { char fname[128]; char sysvar[] = "/proc/sys/net/ipv6/conf/%s/accept_dad"; int fd; snprintf(fname, 128, sysvar, ifname); fd = open(fname, O_WRONLY); test_assert(write(fd, "0", 1) == 1, "write"); close(fd); } /* create a bridge with a couple of tap interfaces */ static void create_interfaces(lc_ctx_t *lctx) { errno = 0; for (int i = 0; i < IF_COUNT; i++) { test_assert(lc_tap_create(ifname[i]) != -1, "lc_tap_create"); perror("lc_tap_create"); disable_dad(ifname[i]); /* otherwise we need to sleep 2s for DAD */ test_assert(lc_link_set(lctx, ifname[i], LC_IF_UP) == 0, "lc_link_set %s UP", ifname[i]); perror("lc_link_set"); } } int main(void) { lc_ctx_t * lctx; lc_socket_t * sock[IF_COUNT]; lc_channel_t * chan; pthread_attr_t attr = {0}; pthread_t thread[IF_COUNT]; struct timespec ts; int dir[IF_COUNT] = { 0, 1, 2 }; test_require_linux(); test_cap_require(CAP_NET_ADMIN); test_name("lc_socket_bind()"); lctx = lc_ctx_new(); chan = lc_channel_new(lctx, channel_name); create_interfaces(lctx); sem_init(&sem_ready, 0, 0); sem_init(&sem_done, 0, 0); pthread_attr_init(&attr); for (int i = 0; i < IF_COUNT; i++) { pthread_create(&thread[i], &attr, &recv_thread, &dir[i]); } pthread_attr_destroy(&attr); /* recv threads are ready */ for (int i = 0; i < IF_COUNT; i++) sem_wait(&sem_ready); sem_destroy(&sem_ready); for (int i = 0; i < IF_COUNT; i++) { sock[i] = lc_socket_new(lctx); lc_socket_loop(sock[i], 1); lc_channel_bind(sock[i], chan); test_assert(lc_socket_bind(sock[i], if_nametoindex(ifname[i])) == 0, "lc_socket_bind: %s", strerror(errno)); lc_channel_send(chan, hail[i], strlen(hail[i]), 0); } /* wait for recv threads */ test_assert(!clock_gettime(CLOCK_REALTIME, &ts), "clock_gettime()"); ts.tv_sec += WAITS; for (int i = 0; i < IF_COUNT; i++) { test_assert(!sem_timedwait(&sem_done, &ts), "timeout"); } sem_destroy(&sem_done); for (int i = 0; i < IF_COUNT; i++) { test_log("devoir: %s\n", recvbuf[i]); } for (int i = 0; i < IF_COUNT; i++) { pthread_cancel(thread[i]); pthread_join(thread[i], NULL); test_expect(hail[i], recvbuf[i]); } destroy_interfaces(lctx); lc_ctx_free(lctx); return test_status; } librecast/test/0000-0018.c000066400000000000000000000046111502456746400151350ustar00rootroot00000000000000#include "testnet.h" #include #include #include #include #include #include #include #include #include #include #define WAITS 1 static char channame[][6] = { "red", "green", "blue" }; enum { channels = sizeof channame / sizeof channame[0] }; static sem_t sem; void *recv_thread(void *arg) { lc_ctx_t *lctx = lc_ctx_new(); lc_socket_t *sock = lc_socket_new(lctx); test_assert(lctx != NULL, "lc_ctx_new() - recv thread"); test_assert(sock != NULL, "lc_socket_new() - recv thread"); lc_channel_t *chan[channels]; char buf[BUFSIZ]; for (int i = 0; i < channels; i++) { chan[i] = lc_channel_new(lctx, channame[i]); lc_channel_bind(sock, chan[i]); test_log("channel %s bound to socket %i", channame[i], chan[i]->sock->sock); lc_channel_join(chan[i]); } sem_post(&sem); /* ready */ for (int i = 0; i < channels; i++) { lc_socket_recv(sock, buf, BUFSIZ, 0); sem_post(&sem); } lc_ctx_free(lctx); return arg; } int main(void) { lc_ctx_t *lctx; lc_socket_t *sock; lc_channel_t *chan[channels]; pthread_attr_t attr = {0}; pthread_t thread; struct timespec ts; test_name("lc_socket_send()"); test_require_net(TEST_NET_BASIC); lctx = lc_ctx_new(); test_assert(lctx != NULL, "lc_ctx_new() - send thread"); sock = lc_socket_new(lctx); test_assert(sock != NULL, "lc_socket_new() - send thread"); lc_socket_loop(sock, 1); /* create some channels and bind to the same socket */ for (int i = 0; i < channels; i++) { int rc; chan[i] = lc_channel_new(lctx, channame[i]); rc = lc_channel_bind(sock, chan[i]); test_assert(rc == 0, "lc_channel_bind() = %i", rc); perror("lc_channel_bind"); } /* fire up receiver thread */ sem_init(&sem, 0, 0); pthread_attr_init(&attr); pthread_create(&thread, &attr, &recv_thread, NULL); pthread_attr_destroy(&attr); sem_wait(&sem); /* send to all channels which are bound to this socket */ lc_socket_send(sock, channame[0], strlen(channame[0]), 0); /* wait for recv thread */ test_assert(!clock_gettime(CLOCK_REALTIME, &ts), "clock_gettime()"); ts.tv_sec += WAITS; for (int i = 0; i < channels; i++) { /* ensure we received ALL channels */ test_assert(!sem_timedwait(&sem, &ts), "timeout"); } sem_destroy(&sem); pthread_cancel(thread); pthread_join(thread, NULL); lc_ctx_free(lctx); return test_status; } librecast/test/0000-0019.c000066400000000000000000000065021502456746400151370ustar00rootroot00000000000000#include "testnet.h" #include #include #include #include #include #include #include #define WAITS 1 static sem_t sem; volatile ssize_t byt_recv, byt_sent; static char channame[] = "0000-0019"; static char data[] = "black lives matter"; void *testthread(void *arg) { lc_ctx_t *lctx; lc_socket_t *sock; lc_channel_t *chan; lc_message_t msg; char buf[BUFSIZ]; lc_msg_init(&msg); msg.data = buf; msg.len = BUFSIZ; lctx = lc_ctx_new(); test_assert(lctx != NULL, "lc_ctx_new()"); sock = lc_socket_new(lctx); test_assert(sock != NULL, "lc_socket_new()"); chan = lc_channel_new(lctx, channame); test_assert(chan != NULL, "lc_channel_new()"); test_assert(lc_channel_bind(sock, chan) == 0, "lc_channel_bind()"); test_assert(lc_channel_join(chan) == 0, "lc_channel_join()"); sem_post(&sem); /* tell send thread we're ready */ byt_recv = lc_msg_recv(sock, &msg); test_log("recv %zi bytes\n", byt_recv); test_assert(msg.op == LC_OP_PING, "opcode matches"); test_expectn(data, msg.data, msg.len); /* got our data back */ lc_msg_free(&msg); lc_ctx_free(lctx); sem_post(&sem); /* tell send thread we're done */ return arg; } int main(void) { lc_ctx_t *lctx; lc_socket_t *sock; lc_channel_t *chan; lc_message_t msg; pthread_t thread; struct timespec ts; unsigned op; int rc; test_name("lc_msg_send() / lc_msg_recv() - blocking network recv"); test_require_net(TEST_NET_BASIC); /* fire up test thread */ rc = sem_init(&sem, 0, 0); test_assert(rc == 0, "sem_init returned %i", rc); if (rc) return test_status; rc = pthread_create(&thread, NULL, &testthread, NULL); test_assert(rc == 0, "pthread_create()"); if (rc) goto err_sem_destroy; rc = sem_wait(&sem); /* recv thread is ready */ test_assert(rc == 0, "sem_wait()"); if (rc) goto err_pthread_cancel; /* Librecast Context, Socket + Channel */ lctx = lc_ctx_new(); test_assert(lctx != NULL, "lc_ctx_new()"); if (!lctx) goto err_ctx_free; sock = lc_socket_new(lctx); test_assert(sock != NULL, "lc_socket_new()"); if (!sock) goto err_ctx_free; chan = lc_channel_new(lctx, channame); test_assert(chan != NULL, "lc_channel_new()"); if (!chan) goto err_ctx_free; rc = lc_socket_loop(sock, 1); /* talking to ourselves, set loopback */ test_assert(rc == 0, "lc_socket_loop"); if (rc) goto err_ctx_free; rc = lc_channel_bind(sock, chan); test_assert(rc == 0, "lc_channel_bind"); if (rc) goto err_ctx_free; /* send msg with PING opcode */ op = LC_OP_PING; lc_msg_init_data(&msg, &data, strlen(data) + 1, NULL, NULL); lc_msg_set(&msg, LC_ATTR_OPCODE, &op); byt_sent = lc_msg_send(chan, &msg); test_assert(byt_sent > 0, "lc_msg_send() returned %zi", byt_sent); if (byt_sent == -1) goto err_msg_free; lc_msg_free(&msg); /* clear struct before recv */ /* wait for recv thread */ rc = clock_gettime(CLOCK_REALTIME, &ts); test_assert(rc == 0, "clock_gettime()"); if (rc) goto err_msg_free; ts.tv_sec += WAITS; rc = sem_timedwait(&sem, &ts); test_assert(rc == 0, "timeout"); test_assert(byt_sent == byt_recv, "bytes sent (%zi) == bytes received (%zi)", byt_sent, byt_recv); /* clean up */ err_msg_free: lc_msg_free(&msg); err_ctx_free: lc_ctx_free(lctx); err_pthread_cancel: pthread_cancel(thread); pthread_join(thread, NULL); err_sem_destroy: sem_destroy(&sem); return test_status; } librecast/test/0000-0020.c000066400000000000000000000040101502456746400151170ustar00rootroot00000000000000#include "test.h" #include int main(void) { char data[] = "life, the universe and everything"; size_t len = strlen(data); int op = LC_OP_PING; int *getint; size_t *getsize; void *ptr; test_name("lc_msg_set() / lc_msg_get()"); lc_message_t msg; lc_msg_init(&msg); test_assert(lc_msg_set(NULL, LC_ATTR_DATA, NULL) == LC_ERROR_INVALID_PARAMS, "lc_msg_set(): msg == NULL"); test_assert(lc_msg_set(&msg, 9999, NULL) == LC_ERROR_MSG_ATTR_UNKNOWN, "lc_msg_set(): invalid attr"); test_assert(lc_msg_set(&msg, LC_ATTR_LEN, &len) == 0, "lc_msg_set(): set LC_ATTR_LEN"); test_assert(len == strlen(data), "len unmodified by lc_msg_set()"); test_assert(lc_msg_set(&msg, LC_ATTR_OPCODE, &op) == 0, "lc_msg_set(): set opcode"); test_assert(lc_msg_set(&msg, LC_ATTR_DATA, NULL) == 0, "lc_msg_set(): set NULL data"); test_assert(lc_msg_set(&msg, LC_ATTR_DATA, &data) == 0, "lc_msg_set(): set data"); test_assert(lc_msg_get(NULL, LC_ATTR_DATA, &ptr) == LC_ERROR_INVALID_PARAMS, "lc_msg_get(): msg == NULL"); test_assert(lc_msg_get(&msg, 9999, &ptr) == LC_ERROR_MSG_ATTR_UNKNOWN, "lc_msg_get(): invalid attr"); test_assert(lc_msg_get(&msg, LC_ATTR_DATA, NULL) == LC_ERROR_INVALID_PARAMS, "lc_msg_get(): NULL value ptr"); test_assert(lc_msg_get(&msg, LC_ATTR_DATA, &ptr) == 0, "lc_msg_get(): get data value"); test_expect(data, (char *)ptr); test_assert(len == strlen(data), "len unmodified by lc_msg_set() wilma found a bug"); test_assert(lc_msg_get(&msg, LC_ATTR_OPCODE, (void **)&getint) == 0, "lc_msg_get(): get opcode value"); test_assert(len == strlen(data), "len unmodified by lc_msg_set() barney found a bug"); test_assert(op == *getint, "lc_msg_get(): check opcode"); test_assert(lc_msg_get(&msg, LC_ATTR_LEN, (void **)&getsize) == 0, "lc_msg_get(): get length"); test_assert(len == strlen(data), "len unmodified by lc_msg_set() fred found a bug"); test_log("%i == %i", len, *getsize); test_assert(len == *getsize, "lc_msg_get(): check length"); return test_status; } librecast/test/0000-0021.c000066400000000000000000000050041502456746400151240ustar00rootroot00000000000000#include "testnet.h" #include #include #include #include #include #include #include #include #include #include #define WAITS 1 static char channame[][6] = { "red", "green", "blue" }; enum { channels = sizeof channame / sizeof channame[0] }; static sem_t sem; void *recv_thread(void *arg) { lc_ctx_t *lctx = lc_ctx_new(); lc_socket_t *sock = lc_socket_new(lctx); test_assert(lctx != NULL, "lc_ctx_new() - recv thread"); test_assert(sock != NULL, "lc_socket_new() - recv thread"); lc_channel_t *chan[channels]; char buf[BUFSIZ]; for (int i = 0; i < channels; i++) { chan[i] = lc_channel_new(lctx, channame[i]); lc_channel_bind(sock, chan[i]); test_log("channel %s bound to socket %i", channame[i], chan[i]->sock->sock); lc_channel_join(chan[i]); } sem_post(&sem); /* ready */ for (int i = 0; i < channels; i++) { lc_socket_recv(sock, buf, BUFSIZ, 0); sem_post(&sem); } lc_ctx_free(lctx); return arg; } int main(void) { lc_ctx_t *lctx; lc_socket_t *sock; lc_channel_t *chan[channels]; pthread_attr_t attr = {0}; pthread_t thread; struct timespec ts; test_name("lc_socket_sendmsg()"); test_require_net(TEST_NET_BASIC); lctx = lc_ctx_new(); test_assert(lctx != NULL, "lc_ctx_new() - send thread"); sock = lc_socket_new(lctx); test_assert(sock != NULL, "lc_socket_new() - send thread"); lc_socket_loop(sock, 1); /* create some channels and bind to the same socket */ for (int i = 0; i < channels; i++) { int rc; chan[i] = lc_channel_new(lctx, channame[i]); rc = lc_channel_bind(sock, chan[i]); test_assert(rc == 0, "lc_channel_bind() = %i", rc); perror("lc_channel_bind"); } /* fire up receiver thread */ sem_init(&sem, 0, 0); pthread_attr_init(&attr); pthread_create(&thread, &attr, &recv_thread, NULL); pthread_attr_destroy(&attr); sem_wait(&sem); /* send to all channels which are bound to this socket */ struct iovec iov = { .iov_base = channame[0], .iov_len = strlen(channame[0]) }; struct msghdr msg = { .msg_iov = &iov, .msg_iovlen = 1 }; lc_socket_sendmsg(sock, &msg, 0); /* wait for recv thread */ test_assert(!clock_gettime(CLOCK_REALTIME, &ts), "clock_gettime()"); ts.tv_sec += WAITS; for (int i = 0; i < channels; i++) { /* decrement semaphore once per channel */ test_assert(!sem_timedwait(&sem, &ts), "timeout"); } sem_destroy(&sem); pthread_cancel(thread); pthread_join(thread, NULL); lc_ctx_free(lctx); return test_status; } librecast/test/0000-0022.c000066400000000000000000000056541502456746400151400ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2024 Brett Sheffield */ #include "test.h" #include #include #include #define JOBS 42 static void *godot(void *arg) { test_log("%s", __func__); sem_post((sem_t *)arg); return NULL; } int main(void) { lc_ctx_t *lctx; sem_t semlock; struct timespec timeout; int nthreads = 1; int rc; test_name("lc_ctx_qpool_init() / lc_ctx_qpool_resize() / lc_ctx_qpool_free()"); lctx = lc_ctx_new(); if (!test_assert(lctx != NULL, "lc_ctx_new()")) return test_status; /* create a single thread and queue and free it */ rc = lc_ctx_qpool_init(lctx, nthreads); if (!test_assert(rc == 0, "lc_ctx_qpool_init()")) goto err_ctx_free; test_assert(lctx->nthreads == nthreads, "nthreads (%i == %i)", lctx->nthreads, nthreads); test_assert(lctx->q != NULL, "context queue allocated"); rc = lc_ctx_qpool_free(lctx); if (!test_assert(rc == 0, "lc_ctx_qpool_free()")) goto err_ctx_free; /* create a single thread and queue */ rc = lc_ctx_qpool_init(lctx, nthreads); if (!test_assert(rc == 0, "lc_ctx_qpool_init()")) goto err_ctx_free; /* call lc_ctx_qpool_resize() with unchanged nthreads (NOOP) */ rc = lc_ctx_qpool_resize(lctx, nthreads); if (!test_assert(rc == 0, "lc_ctx_qpool_resize() (no resize)")) goto err_ctx_free; test_assert(lctx->nthreads == nthreads, "nthreads (%i == %i)", lctx->nthreads, nthreads); /* double the number of threads a few times */ for (nthreads = 2; nthreads <= 16; nthreads <<= 1) { test_log("resizing qpool => %i\n", nthreads); rc = lc_ctx_qpool_resize(lctx, nthreads); if (!test_assert(rc == 0, "lc_ctx_qpool_resize() => %i", nthreads)) goto err_ctx_free; test_assert(lctx->nthreads == nthreads, "nthreads (%i == %i)", lctx->nthreads, nthreads); test_assert(lctx->q != NULL, "context queue allocated"); } /* now decrease threads */ nthreads = 7; test_log("decreasing pool to %i\n", nthreads); rc = lc_ctx_qpool_resize(lctx, nthreads); if (!test_assert(rc == 0, "lc_ctx_qpool_resize() => %i", nthreads)) goto err_ctx_free; test_assert(lctx->nthreads == nthreads, "nthreads (%i == %i)", lctx->nthreads, nthreads); test_assert(lctx->q != NULL, "context queue allocated"); /* push some jobs onto the queue */ sem_init(&semlock, 0, 0); for (int i = 0; i < JOBS; i++) q_push(lc_ctx_q(lctx), &godot, &semlock); clock_gettime(CLOCK_REALTIME, &timeout); timeout.tv_sec++; for (int i = 0; i < JOBS; i++) { test_assert(sem_timedwait(&semlock, &timeout) == 0, "timeout waiting for Godot [%i]", i); } sem_destroy(&semlock); /* free the qpool */ rc = lc_ctx_qpool_free(lctx); if (!test_assert(rc == 0, "lc_ctx_qpool_free()")) goto err_ctx_free; /* ensure queue and threads are freed by call to lc_ctx_free() */ rc = lc_ctx_qpool_init(lctx, nthreads); if (!test_assert(rc == 0, "lc_ctx_qpool_init()")) goto err_ctx_free; err_ctx_free: lc_ctx_free(lctx); return test_status; } librecast/test/0000-0023.c000066400000000000000000000012761502456746400151350ustar00rootroot00000000000000#include "test.h" #include #include #include #include #include int main(void) { char addr_in[] = "ff3e:6d38:646e:b0a8:38ca:8bdb:d839:d788"; char addr_out[INET6_ADDRSTRLEN]; struct sockaddr_in6 sa; struct sockaddr_in6 *sar; lc_ctx_t *lctx; lc_channel_t *chan; test_name("lc_channel_init() / lc_channel_sockaddr()"); lctx = lc_ctx_new(); inet_pton(AF_INET6, addr_in, &sa.sin6_addr); chan = lc_channel_init(lctx, &sa); sar = lc_channel_sockaddr(chan); inet_ntop(AF_INET6, &sar->sin6_addr, addr_out, INET6_ADDRSTRLEN); test_expect(addr_in, addr_out); lc_channel_free(chan); lc_ctx_free(lctx); return test_status; } librecast/test/0000-0024.c000066400000000000000000000016331502456746400151330ustar00rootroot00000000000000#include "test.h" #include #include #include int main(void) { lc_ctx_t *lctx; lc_channel_t *orig, *copy; struct in6_addr *oaddr, *caddr; test_name("lc_channel_copy()"); lctx = lc_ctx_new(); test_assert(lctx != NULL, "lc_ctx_new()"); orig = lc_channel_new(lctx, "freedom"); test_assert(orig != NULL, "lc_channel_new() - create orig channel"); copy = lc_channel_copy(lctx, orig); test_assert(copy != NULL, "lc_channel_copy() - copy channel"); if (copy) { /* ensure copy is actually a copy, not just the original */ test_assert(copy != orig, "orig=%p, copy=%p", orig, copy); test_assert(copy->ctx == lctx, "copy->ctx set"); oaddr = &lc_channel_sockaddr(orig)->sin6_addr; caddr = &lc_channel_sockaddr(copy)->sin6_addr; test_assert(!memcmp(caddr, oaddr, sizeof(struct in6_addr)), "copy->address set"); } lc_ctx_free(lctx); return test_status; } librecast/test/0000-0025.c000066400000000000000000000030511502456746400151300ustar00rootroot00000000000000#include "test.h" #include #include #include void dumpaddr(struct in6_addr *addr) { for (int i = 0; i < 128; i++) { fprintf(stderr, "%u", !!isset(addr->s6_addr, i)); } fputc('\n', stderr); } int main(void) { union { uint64_t u64[2]; uint8_t u8[16]; struct in6_addr in6; } addrside; lc_ctx_t *lctx; lc_channel_t *base, *side; unsigned pop; test_name("lc_channel_sideband()"); lctx = lc_ctx_new(); test_assert(lctx != NULL, "lc_ctx_new()"); base = lc_channel_new(lctx, "freedom"); test_assert(base != NULL, "lc_channel_new() - create base channel"); memcpy(&addrside, &lc_channel_sockaddr(base)->sin6_addr, 16); dumpaddr(&addrside.in6); /* lower side band (zero lower 64 bits) */ test_assert((side = lc_channel_sideband(base, 0)) != NULL, "lc_channel_sideband() - lower sideband"); memcpy(&addrside, &lc_channel_sockaddr(side)->sin6_addr, 16); dumpaddr(&addrside.in6); pop = 0; for (int i = 8; i < 16; i++) { pop += __builtin_popcount(addrside.u8[i]); } test_assert(!pop, "lower side band - lower 64 bits zeroed, pop=%u", pop); /* upper side band (lower 64 bits -> 1) */ test_assert((side = lc_channel_sideband(base, UINT64_MAX)) != NULL, "lc_channel_sideband() - lower sideband"); memcpy(&addrside, &lc_channel_sockaddr(side)->sin6_addr, 16); dumpaddr(&addrside.in6); pop = 0; for (int i = 8; i < 16; i++) { pop += __builtin_popcount(addrside.u8[i]); } test_assert(pop == 64, "upper side band - lower 64 bits => 1, pop=%u", pop); lc_ctx_free(lctx); return test_status; } librecast/test/0000-0026.c000066400000000000000000000043401502456746400151330ustar00rootroot00000000000000#include "test.h" #include #include #include #include void dumpaddr(struct in6_addr *addr) { char straddr[INET6_ADDRSTRLEN] = ""; inet_ntop(AF_INET6, addr, straddr, INET6_ADDRSTRLEN); test_log("%s\n", straddr); } int main(void) { lc_ctx_t *lctx; lc_channel_t *base, *side, *rev, *copy; struct in6_addr *bin6 = NULL, *sin6 = NULL; unsigned char key = 42; test_name("lc_channel_sidehash()"); lctx = lc_ctx_new(); test_assert(lctx != NULL, "lc_ctx_new()"); if (!lctx) return test_status; base = lc_channel_new(lctx, "freedom"); test_assert(base != NULL, "lc_channel_new() - create base channel"); if (!base) return test_status; bin6 = lc_channel_in6addr(base); test_assert(bin6 != NULL, "lc_channel_sockaddr(base)"); if (!bin6) return test_status; test_log("base: \n"); dumpaddr(bin6); test_log("base=%p, side=%p\n", (void *)bin6, (void *)sin6); test_assert((side = lc_channel_sidehash(base, &key, sizeof key)) != NULL, "lc_channel_sidehash(1)"); if (!side) return test_status; sin6 = lc_channel_in6addr(side); test_assert(sin6 != NULL, "lc_channel_sockaddr(base)"); if (!sin6) return test_status; test_log("side: \n"); dumpaddr(sin6); test_assert(lc_channel_sockaddr(base) != lc_channel_sockaddr(side), "copy address differs from base"); test_assert(memcmp(sin6->s6_addr, bin6->s6_addr, 16), "side channel and base channel must be different"); /* make sure side channel of side channel isn't the original channel */ rev = lc_channel_sidehash(side, &key, sizeof key); test_assert(rev != NULL, "lc_channel_sidehash(2)"); sin6 = &lc_channel_sockaddr(rev)->sin6_addr; test_assert(memcmp(sin6->s6_addr, bin6->s6_addr, 16), "side side channel and base channel must be different"); test_log("side(2): \n"); dumpaddr(sin6); /* ensure we can regenerate the same channel with same params */ test_assert((copy = lc_channel_sidehash(base, &key, sizeof key)) != NULL, "lc_channel_sidehash(copy)"); bin6 = lc_channel_in6addr(side); sin6 = lc_channel_in6addr(copy); test_assert(!memcmp(sin6->s6_addr, bin6->s6_addr, 16), "side channels must match"); test_log("MUST match:\n"); dumpaddr(bin6); dumpaddr(sin6); lc_ctx_free(lctx); return test_status; } librecast/test/0000-0027.c000066400000000000000000000012211502456746400151270ustar00rootroot00000000000000#include "test.h" #include int main(void) { char in1[] = "hash this"; char in2[] = "hash that"; unsigned char hash1[HASHSIZE]; unsigned char hash2[HASHSIZE]; hash_state state; test_name("hash_init() / hash_update() / hash_final()"); hash_generic(hash1, HASHSIZE, (unsigned char *)in1, strlen(in1)); hash_generic(hash2, HASHSIZE, (unsigned char *)in2, strlen(in2)); test_assert(memcmp(hash1, hash2, HASHSIZE), "hashes must differ"); hash_init(&state, NULL, 0, HASHSIZE); hash_update(&state, (unsigned char *)in1, HASHSIZE); hash_final(&state, hash2, HASHSIZE); /* TODO: tests with keys etc. */ return test_status; } librecast/test/0000-0028.c000066400000000000000000000032151502456746400151350ustar00rootroot00000000000000#include "testnet.h" #include #include #include #include static int logged; int logme(lc_channel_t *chan, lc_message_t *msg, void *logdb) { (void)chan; (void)msg; (void)logdb; logged++; return 0; } void sendmsgs(lc_channel_t *chan, lc_message_t *msg, int msgs) { for (int i = 0; i < msgs; i++) { lc_msg_send(chan, msg); } } int main(void) { lc_ctx_t *lctx; lc_socket_t *sock; lc_channel_t *chan; lc_message_t msg = {0}; struct ifaddrs *ifaddr, *ifa; test_name("lc_msg_logger()"); test_require_net(TEST_NET_BASIC); lctx = lc_ctx_new(); sock = lc_socket_new(lctx); chan = lc_channel_new(lctx, "channel logger"); /* find first interface that supports IPv6 multicast */ test_assert(getifaddrs(&ifaddr) != -1, "getifaddrs()"); for (ifa = ifaddr; ifa; ifa = ifa->ifa_next) { if ((ifa->ifa_flags & IFF_MULTICAST) == IFF_MULTICAST && ifa->ifa_addr && ifa->ifa_addr->sa_family == AF_INET6) { lc_socket_bind(sock, if_nametoindex(ifa->ifa_name)); break; } } freeifaddrs(ifaddr); lc_socket_loop(sock, 1); lc_channel_bind(sock, chan); lc_channel_join(chan); lc_socket_listen(sock, NULL, NULL); sendmsgs(chan, &msg, 3); usleep(1000); /* test with no logger */ test_assert(logged == 0, "(no logger) msgs logged = %i", logged); /* set logger */ __atomic_store_n(&lc_msg_logger, &logme, __ATOMIC_RELEASE); logged = 0; sendmsgs(chan, &msg, 7); usleep(1000); /* stop listen thread before reading logged to prevent data race */ lc_socket_listen_cancel(sock); test_assert(logged == 7, "(msg logger set) msgs logged = %i", logged); lc_ctx_free(lctx); return test_status; } librecast/test/0000-0029.c000066400000000000000000000015451502456746400151420ustar00rootroot00000000000000#include "test.h" #include #include #include #include int main(void) { const char brname[] = "0000-0029"; lc_ctx_t *lctx; test_require_linux(); test_cap_require(CAP_NET_ADMIN); test_name("lc_bridge_add() / lc_bridge_del()"); lctx = lc_ctx_new(); test_assert(lc_bridge_del(lctx, brname) == ENXIO, "lc_bridge_del() - try to delete bridge that doesn't exist"); perror("lc_bridge_del"); test_assert(lc_bridge_add(lctx, brname) == 0, "lc_bridge_add() - add the bridge"); perror("lc_bridge_add"); test_assert(lc_bridge_del(lctx, brname) == 0, "lc_bridge_del() - now delete it successfully"); perror("lc_bridge_add"); test_assert(lc_bridge_del(lctx, brname) == ENXIO, "lc_bridge_del() - try to delete it again and fail"); perror("lc_bridge_del"); lc_ctx_free(lctx); return test_status; } librecast/test/0000-0030.c000066400000000000000000000012111502456746400151200ustar00rootroot00000000000000#include "test.h" #include #include #include int main(void) { char tapname[IFNAMSIZ] = {0}; int rc; test_cap_require(CAP_NET_ADMIN); test_name("lc_tap_create()"); rc = lc_tap_create(tapname); if (rc == -1) { test_log("lc_tap_create() failed: %s", strerror(errno)); test_log("tap creation not supported"); test_assert(errno == ENOTSUP, "lc_tap_create - not supported"); } else { test_log("created tap interface %s", tapname); test_assert(rc > 0, "lc_tap_create - created"); test_assert(if_nametoindex(tapname) > 0, "check idx, ensure tap exists"); close(rc); } return test_status; } librecast/test/0000-0031.c000066400000000000000000000024061502456746400151300ustar00rootroot00000000000000#include "test.h" #include #include #include #include #include #include int sock = -1; int isup(const char *ifname) { struct ifreq ifr = {0}; strncpy(ifr.ifr_name, ifname, IFNAMSIZ - 1); ioctl(sock, SIOCGIFFLAGS, &ifr); return ifr.ifr_flags & IFF_UP; } int main(void) { char tapname[IFNAMSIZ] = {0}; lc_ctx_t *lctx = NULL; test_require_linux(); test_cap_require(CAP_NET_ADMIN); test_name("lc_link_set()"); test_assert(lc_tap_create(tapname) > 0, "lc_tap_create - created"); test_assert(if_nametoindex(tapname) > 0, "check idx, ensure tap exists"); lctx = lc_ctx_new(); test_assert(lctx != NULL, "lc_ctx_new()"); if (!lctx) return test_status; sock = socket(AF_LOCAL, SOCK_STREAM, 0); test_assert(sock != -1, "test socket (AF_LOCAL)"); if (sock == -1) return test_status; test_assert(!isup(tapname), "interface is down"); test_assert(lc_link_set(lctx, tapname, LC_IF_UP) == 0, "bring up interface %s", tapname); test_assert(isup(tapname), "interface is up"); test_assert(lc_link_set(lctx, tapname, LC_IF_DOWN) == 0, "bring down interface %s", tapname); test_assert(!isup(tapname), "interface is down"); lc_ctx_free(lctx); close(sock); return test_status; } librecast/test/0000-0032.c000066400000000000000000000030741502456746400151330ustar00rootroot00000000000000#include "test.h" #include #include #include #include int main(void) { const char brname[] = "0000-0032"; enum { tapcount = 42 }; char tap[tapcount][IFNAMSIZ] = {0}; lc_ctx_t *lctx = NULL; test_require_linux(); test_cap_require(CAP_NET_ADMIN); test_name("lc_bridge_addif() / lc_bridge_delif()"); lctx = lc_ctx_new(); test_assert(lctx != NULL, "lc_ctx_new()"); if (!lctx) return test_status; test_assert(lc_bridge_add(lctx, brname) == 0, "lc_bridge_add()"); for (int i = 0; i < tapcount; i++) { test_assert(lc_tap_create(tap[i]) > 0, "lc_tap_create - created (%i)", i); test_assert(if_nametoindex(tap[i]) > 0, "check idx, ensure tap exists (%i)", i); test_assert(lc_link_set(lctx, tap[i], LC_IF_UP) == 0, "bring up interface %s (%i)", tap[i], i); } test_assert(lc_bridge_addif(lctx, "Scottish Mist", tap[0]) == ENODEV, "lc_bridge_addif() - missing bridge", tap[0]); test_assert(lc_bridge_addif(lctx, brname, "faildev") == ENODEV, "lc_bridge_addif() - missing interface"); test_assert(lc_bridge_delif(lctx, brname, tap[0]) != 0, "lc_bridge_delif() - try to delete if we haven't added"); for (int i = 0; i < tapcount; i++) { test_assert(lc_bridge_addif(lctx, brname, tap[i]) == 0, "lc_bridge_addif() - %s (%i)", tap[i], i); } for (int i = 0; i < tapcount; i++) { test_assert(lc_bridge_delif(lctx, brname, tap[i]) == 0, "lc_bridge_delif() - delete if %i", i); } test_assert(lc_bridge_del(lctx, brname) == 0, "lc_bridge_del()"); lc_ctx_free(lctx); return test_status; } librecast/test/0000-0033.c000066400000000000000000000017011502456746400151270ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2021-2024 Brett Sheffield */ #include "test.h" #include #include #include #include #include #define CHANNELS 16 int main(void) { lc_ctx_t *lctx; lc_channel_t *chan[CHANNELS]; unsigned char *hash[2]; test_name("lc_channel_random()"); lctx = lc_ctx_new(); test_assert(lctx != NULL, "lc_ctx_new()"); if (!lctx) return test_status; for (int i = 0; i < CHANNELS; i++) { chan[i] = lc_channel_random(lctx); test_assert(chan[i] != NULL, "error creating channel %i", i); } for (int i = 0; i < CHANNELS; i++) { for (int j = i + 1; j < CHANNELS; j++) { hash[0] = lc_channel_get_hash(chan[i]); hash[1] = lc_channel_get_hash(chan[j]); test_assert(memcmp(hash[0], hash[1], HASHSIZE), "channels must be different"); } } lc_ctx_free(lctx); return test_status; } librecast/test/0000-0034.c000066400000000000000000000022251502456746400151320ustar00rootroot00000000000000#include "test.h" #include #include int main(void) { #ifdef __linux__ char dev[IFNAMSIZ] = ""; char *testdev = "testdev"; char *testdyn = "testdev%d"; int fd; #endif test_require_linux(); test_cap_require(CAP_NET_ADMIN); test_name("lc_tuntap_create()"); #ifdef IFF_TUN /* blank device name => tun%d */ if (!test_assert((fd = lc_tuntap_create(dev, IFF_TUN)) > 0, "lc_tuntap_create()")) perror("lc_tuntap_create()"); test_log("interface name: %s", dev); close(fd); /* use device name if supplied */ strcpy(dev, testdev); if (!test_assert((fd = lc_tuntap_create(dev, IFF_TUN)) > 0, "lc_tuntap_create()")) perror("lc_tuntap_create()"); test_strcmp(dev, testdev, "interface name %s", dev); test_log("interface name: %s", dev); close(fd); /* test dynamically numbered (%d format string) devicename */ strcpy(dev, testdyn); if (!test_assert((fd = lc_tuntap_create(dev, IFF_TUN)) > 0, "lc_tuntap_create()")) perror("lc_tuntap_create()"); test_strcmp(dev, "testdev0", "interface name %s", dev); test_log("interface name: %s", dev); close(fd); #else test_assert(0, "IFF_TUN not defined"); #endif return test_status; } librecast/test/0000-0035.c000066400000000000000000000023471502456746400151400ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2017-2022 Brett Sheffield */ #include "test.h" #include int main(void) { lc_ctx_t *lctx; lc_channel_t *chan; lc_key_t key ={0}; char *shortkey = "shortkey"; size_t keylen = strlen(shortkey); int rc; test_name("Channel key management functions"); lctx = lc_ctx_new(); chan = lc_channel_new(lctx, "Librecast"); rc = lc_channel_setkey(chan, &key, -1); test_assert(rc == -1, "lc_channel_setkey() invalid"); rc = lc_channel_setkey(chan, &key, LC_CODE_SYMM); test_assert(rc == 0, "lc_channel_setkey() success"); rc = lc_channel_set_sym_key(chan, (unsigned char *)shortkey, keylen); test_assert(rc == 0, "lc_channel_set_sym_key() success"); rc = lc_channel_set_pub_key(chan, (unsigned char *)shortkey, keylen); test_assert(rc == 0, "lc_channel_set_pub_key() success"); lc_key_t tmpkey = {0}; rc = lc_channel_getkey(chan, &tmpkey, LC_CODE_SYMM); test_assert(rc == 0, "lc_channel_getkey() success"); test_expect(shortkey, (char *)tmpkey.key); memset(&tmpkey, 0, sizeof tmpkey); lc_channel_getkey(chan, &tmpkey, LC_CODE_PUBK); test_expect(shortkey, (char *)tmpkey.key); lc_ctx_free(lctx); return test_status; } librecast/test/0000-0036.c000066400000000000000000000073361502456746400151440ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2017-2025 Brett Sheffield */ #include "testnet.h" #include #include #include #include #include #include #include #include #define WAITS 1 #ifdef HAVE_LIBSODIUM static sem_t sem; static ssize_t byt_recv, byt_sent, ohead; static char channame[] = "0000-0036"; static unsigned char key[crypto_secretbox_KEYBYTES]; static int encryption_on; void *testthread(void *arg) { lc_ctx_t *lctx; lc_socket_t *sock; lc_channel_t *chan; lctx = lc_ctx_new(); test_assert(lctx != NULL, "lc_ctx_new()"); sock = lc_socket_new(lctx); test_assert(sock != NULL, "lc_socket_new()"); chan = lc_channel_new(lctx, channame); test_assert(chan != NULL, "lc_channel_new()"); test_assert(lc_channel_bind(sock, chan) == 0, "lc_channel_bind()"); test_assert(lc_channel_join(chan) == 0, "lc_channel_join()"); if (encryption_on) { lc_channel_set_sym_key(chan, key, crypto_secretbox_KEYBYTES); lc_channel_coding_set(chan, LC_CODE_SYMM); ohead = crypto_secretbox_MACBYTES + crypto_secretbox_NONCEBYTES; } sem_post(&sem); /* tell send thread we're ready */ byt_recv = lc_socket_recv(sock, (char *)arg, BUFSIZ, 0); lc_ctx_free(lctx); sem_post(&sem); /* tell send thread we're done */ return arg; } #endif int main(void) { #ifndef HAVE_LIBSODIUM return test_skip("lc_channel_send() / lc_socket_recv() - symmetric encryption"); #else lc_ctx_t *lctx; lc_socket_t *sock; lc_channel_t *chan; pthread_t thread; struct timespec ts; char buf[] = "liberté"; char recvbuf[BUFSIZ] = ""; test_name("lc_channel_send() / lc_socket_recv() - symmetric encryption"); test_require_net(TEST_NET_BASIC); /* fire up test thread */ sem_init(&sem, 0, 0); pthread_create(&thread, NULL, &testthread, &recvbuf); sem_wait(&sem); /* recv thread is ready */ /* Librecast Context, Socket + Channel */ lctx = lc_ctx_new(); test_assert(lctx != NULL, "lc_ctx_new()"); sock = lc_socket_new(lctx); test_assert(sock != NULL, "lc_socket_new()"); chan = lc_channel_new(lctx, channame); test_assert(chan != NULL, "lc_channel_new()"); lc_socket_loop(sock, 1); /* talking to ourselves, set loopback */ lc_channel_bind(sock, chan); /* generate and set symmetric key on sender */ crypto_secretbox_keygen(key); lc_channel_set_sym_key(chan, key, crypto_secretbox_KEYBYTES); lc_channel_coding_set(chan, LC_CODE_SYMM); /* send msg with PING opcode */ byt_sent = lc_channel_send(chan, buf, sizeof buf, 0); /* wait for recv thread */ test_assert(!clock_gettime(CLOCK_REALTIME, &ts), "clock_gettime()"); ts.tv_sec += WAITS; test_assert(!sem_timedwait(&sem, &ts), "timeout"); pthread_cancel(thread); pthread_join(thread, NULL); test_assert(memcmp(buf, recvbuf, sizeof buf) != 0, "data doesn't match with encryption"); /* run testthread again with encryption key set */ encryption_on = 1; pthread_create(&thread, NULL, &testthread, &recvbuf); sem_wait(&sem); /* recv thread is ready */ byt_sent = lc_channel_send(chan, buf, sizeof buf, 0); /* wait for recv thread */ test_assert(!clock_gettime(CLOCK_REALTIME, &ts), "clock_gettime()"); ts.tv_sec += WAITS; test_assert(!sem_timedwait(&sem, &ts), "timeout"); sem_destroy(&sem); /* test we can decrypt message */ if (byt_recv > 0) { test_assert(byt_recv == sizeof buf, "received %zi bytes, expected %zu", byt_recv, sizeof buf); test_assert(memcmp(buf, recvbuf, sizeof buf) == 0, "data decrypted"); } test_assert(byt_sent - ohead == byt_recv, "bytes sent (%zi) == bytes received (%zi)", byt_sent - ohead, byt_recv); /* clean up */ pthread_cancel(thread); pthread_join(thread, NULL); lc_ctx_free(lctx); return test_status; #endif } librecast/test/0000-0037.c000066400000000000000000000104061502456746400151350ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2017-2022 Brett Sheffield */ #include "testnet.h" #include #include #include #include #include #include #include #include #define WAITS 1 #ifdef HAVE_LIBSODIUM static sem_t sem; static ssize_t byt_recv, byt_sent, ohead; static char channame[] = "0000-0037"; static char data[] = "black lives matter"; static unsigned char key[crypto_secretbox_KEYBYTES]; static int encryption_on; void *testthread(void *arg) { lc_ctx_t *lctx; lc_socket_t *sock; lc_channel_t *chan; lc_message_t *msg = (lc_message_t *)arg; char buf[BUFSIZ]; lc_msg_init(msg); msg->data = buf; msg->len = BUFSIZ; lctx = lc_ctx_new(); test_assert(lctx != NULL, "lc_ctx_new()"); sock = lc_socket_new(lctx); test_assert(sock != NULL, "lc_socket_new()"); chan = lc_channel_new(lctx, channame); test_assert(chan != NULL, "lc_channel_new()"); test_assert(lc_channel_bind(sock, chan) == 0, "lc_channel_bind()"); test_assert(lc_channel_join(chan) == 0, "lc_channel_join()"); if (encryption_on) { lc_channel_set_sym_key(chan, key, crypto_secretbox_KEYBYTES); lc_channel_coding_set(chan, LC_CODE_SYMM); ohead = crypto_secretbox_MACBYTES + crypto_secretbox_NONCEBYTES; } sem_post(&sem); /* tell send thread we're ready */ byt_recv = lc_msg_recv(sock, msg); lc_ctx_free(lctx); sem_post(&sem); /* tell send thread we're done */ return arg; } #endif int main(void) { #ifndef HAVE_LIBSODIUM return test_skip("lc_msg_send() / lc_msg_recv() - symmetric encryption"); #else lc_ctx_t *lctx; lc_socket_t *sock; lc_channel_t *chan; lc_message_t msg_out, msg_in; pthread_t thread; struct timespec ts; unsigned op; test_name("lc_msg_send() / lc_msg_recv() - symmetric encryption"); test_require_net(TEST_NET_BASIC); /* fire up test thread */ sem_init(&sem, 0, 0); pthread_create(&thread, NULL, &testthread, &msg_in); sem_wait(&sem); /* recv thread is ready */ /* Librecast Context, Socket + Channel */ lctx = lc_ctx_new(); test_assert(lctx != NULL, "lc_ctx_new()"); sock = lc_socket_new(lctx); test_assert(sock != NULL, "lc_socket_new()"); chan = lc_channel_new(lctx, channame); test_assert(chan != NULL, "lc_channel_new()"); lc_socket_loop(sock, 1); /* talking to ourselves, set loopback */ lc_channel_bind(sock, chan); /* generate and set symmetric key on sender */ crypto_secretbox_keygen(key); lc_channel_set_sym_key(chan, key, crypto_secretbox_KEYBYTES); lc_channel_coding_set(chan, LC_CODE_SYMM); /* send msg with PING opcode */ op = LC_OP_PING; lc_msg_init_data(&msg_out, data, strlen(data), NULL, NULL); test_log("msg (out): '%.*s'\n", (int)msg_out.len, msg_out.data); lc_msg_set(&msg_out, LC_ATTR_OPCODE, &op); byt_sent = lc_msg_send(chan, &msg_out); lc_msg_free(&msg_out); /* clear struct before recv */ /* wait for recv thread */ test_assert(!clock_gettime(CLOCK_REALTIME, &ts), "clock_gettime()"); ts.tv_sec += WAITS; test_assert(!sem_timedwait(&sem, &ts), "timeout"); pthread_cancel(thread); pthread_join(thread, NULL); test_assert(memcmp(data, msg_in.data, strlen(data)) != 0, "encrypted data doesn't match"); lc_msg_free(&msg_in); /* run testthread again with encryption key set */ encryption_on = 1; pthread_create(&thread, NULL, &testthread, &msg_in); sem_wait(&sem); /* recv thread is ready */ op = LC_OP_PING; lc_msg_init_data(&msg_out, data, strlen(data), NULL, NULL); test_log("msg (out): '%.*s'\n", (int)msg_out.len, msg_out.data); lc_msg_set(&msg_out, LC_ATTR_OPCODE, &op); byt_sent = lc_msg_send(chan, &msg_out); lc_msg_free(&msg_out); /* clear struct before recv */ /* wait for recv thread */ test_assert(!clock_gettime(CLOCK_REALTIME, &ts), "clock_gettime()"); ts.tv_sec += WAITS; test_assert(!sem_timedwait(&sem, &ts), "timeout"); sem_destroy(&sem); test_assert(memcmp(data, msg_in.data, strlen(data)) == 0, "decrypted data matches"); test_assert(msg_in.op == LC_OP_PING, "opcode matches"); test_assert(byt_sent - ohead == byt_recv, "bytes sent (%zi) == bytes received (%zi)", byt_sent, byt_recv); /* clean up */ pthread_cancel(thread); pthread_join(thread, NULL); lc_msg_free(&msg_out); lc_msg_free(&msg_in); lc_ctx_free(lctx); return test_status; #endif } librecast/test/0000-0038.c000066400000000000000000000100141502456746400151310ustar00rootroot00000000000000#include "testnet.h" #include #include #include #include #define WAITS 1 #ifdef HAVE_LIBSODIUM static char channel_name[] = "0000-0016"; static sem_t sem; static ssize_t bytes = -1; static unsigned char key[crypto_secretbox_KEYBYTES]; static int encryption_on = 0; static char recvbuf[8]; static char recvbuf2[8]; static void *listen_thread(void *arg) { lc_ctx_t * lctx; lc_socket_t * sock; lc_channel_t * chan; struct iovec iov[2]; struct msghdr msg = {0}; lctx = lc_ctx_new(); sock = lc_socket_new(lctx); chan = lc_channel_new(lctx, channel_name); iov[0].iov_base = recvbuf; iov[0].iov_len = sizeof recvbuf; iov[1].iov_base = recvbuf2; iov[1].iov_len = sizeof recvbuf2; msg.msg_iov = iov; msg.msg_iovlen = 2; lc_channel_bind(sock, chan); lc_channel_join(chan); if (encryption_on) { lc_channel_set_sym_key(chan, key, crypto_secretbox_KEYBYTES); lc_channel_coding_set(chan, LC_CODE_SYMM); } sem_post(&sem); /* tell send thread we're ready */ bytes = lc_socket_recvmsg(sock, &msg, 0); if (bytes == -1) perror("lc_socket_recvmsg"); sem_post(&sem); /* tell send thread we're done */ lc_ctx_free(lctx); return arg; } #endif int main(void) { #ifndef HAVE_LIBSODIUM return test_skip("lc_channel_sendmsg() / lc_socket_recvmsg() - symmetric encryption"); #else lc_ctx_t * lctx; lc_socket_t * sock; lc_channel_t * chan; pthread_t thread; struct timespec ts; char buf[8] = "liberte"; char buf2[8] = "egalite"; struct iovec iov[2]; struct msghdr msg = {0}; size_t sentbyt; test_name("lc_channel_sendmsg() / lc_socket_recvmsg() - symmetric encryption"); test_require_net(TEST_NET_BASIC); sem_init(&sem, 0, 0); pthread_create(&thread, NULL, &listen_thread, &recvbuf); sem_wait(&sem); /* recv thread is ready */ lctx = lc_ctx_new(); sock = lc_socket_new(lctx); chan = lc_channel_new(lctx, channel_name); /* generate and set symmetric key on sender */ crypto_secretbox_keygen(key); lc_channel_set_sym_key(chan, key, crypto_secretbox_KEYBYTES); lc_channel_coding_set(chan, LC_CODE_SYMM); iov[0].iov_base = buf; iov[0].iov_len = strlen(buf) + 1; iov[1].iov_base = buf2; iov[1].iov_len = strlen(buf2) + 1; msg.msg_iov = iov; msg.msg_iovlen = 2; sentbyt = 0; for (size_t z = 0; z < (size_t)msg.msg_iovlen; z++) sentbyt += iov[z].iov_len; lc_socket_loop(sock, 1); lc_channel_bind(sock, chan); lc_channel_sendmsg(chan, &msg, 0); test_assert(!clock_gettime(CLOCK_REALTIME, &ts), "clock_gettime()"); ts.tv_sec += WAITS; test_assert(!sem_timedwait(&sem, &ts), "timeout"); sem_timedwait(&sem, &ts); pthread_cancel(thread); pthread_join(thread, NULL); test_assert((size_t)bytes == sentbyt, "0: received %zi bytes, expected %zu", bytes, sentbyt); /* we can't really prove the data is encrypted, but we can at least * check it isn't the same as what we sent */ test_assert(memcmp(buf, recvbuf, sizeof buf - 1) != 0, "data doesn't match with encryption"); /* now receive again with key */ encryption_on = 1; pthread_create(&thread, NULL, &listen_thread, &recvbuf); sem_wait(&sem); /* recv thread is ready */ iov[0].iov_base = buf; iov[0].iov_len = strlen(buf) + 1; test_log("iov[0].iov_len = %zu\n", iov[0].iov_len); iov[1].iov_base = buf2; iov[1].iov_len = strlen(buf2) + 1; test_log("iov[1].iov_len = %zu\n", iov[1].iov_len); msg.msg_iov = iov; msg.msg_iovlen = 2; sentbyt = 0; for (size_t z = 0; z < (size_t)msg.msg_iovlen; z++) sentbyt += iov[z].iov_len; lc_channel_sendmsg(chan, &msg, 0); test_assert(!clock_gettime(CLOCK_REALTIME, &ts), "clock_gettime()"); ts.tv_sec += WAITS; test_assert(!sem_timedwait(&sem, &ts), "timeout"); sem_timedwait(&sem, &ts); sem_destroy(&sem); pthread_cancel(thread); pthread_join(thread, NULL); test_assert((size_t)bytes == sentbyt, "1: returned %zi bytes, expected %zu", bytes, sentbyt); test_assert(memcmp(buf, recvbuf, sizeof buf - 1) == 0, "data decrypts [0]"); test_assert(memcmp(buf2, recvbuf2, sizeof buf2 - 1) == 0, "data decrypts [1]"); lc_ctx_free(lctx); return test_status; #endif } librecast/test/0000-0039.c000066400000000000000000000110601502456746400151340ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2017-2024 Brett Sheffield */ #include "testnet.h" #include #include #include #include #include #include #include #include #include #undef TESTDEBUG #ifdef TESTDEBUG # define PKTS 10 # define PKTSZ 4 #else # define PKTS 20 # define PKTSZ 1024 #endif #define WAITS 20 #ifdef HAVE_LIBLCRQ enum { TID_SEND, TID_RECV }; static const size_t SZ = PKTS * PKTSZ + 5; static char channel_name[] = "0000-0039"; static sem_t receiver_ready, timeout; #ifdef TESTDEBUG static void dumppkt(uint8_t *pkt, int haseq) { uint16_t seq; uint8_t *dat = pkt; if (haseq) { dat += sizeof seq; seq = ntohs(*(uint16_t *)pkt); fprintf(stderr, "%u: ", seq); } else fprintf(stderr, " "); for (size_t z = 0; z < PKTSZ * 8; z++) { if (isset(dat, z)) putc('1', stderr); else putc('0', stderr); } putc('\n', stderr); } static void dump_bufs(uint8_t buf[2][SZ]) { for (size_t p = 0; p < PKTS; p++) { fprintf(stderr, "%zu: ", p); for (int i = 0; i < 2; i++) { for (size_t z = 0; z < PKTSZ * 8; z++) { uint8_t *b = buf[i]; if (isset(b, p * PKTSZ * 8 + z)) putc('1', stderr); else putc('0', stderr); } putc(' ', stderr); } putc('\n', stderr); } putc('\n', stderr); } #endif static void generate_source_data(uint8_t *buf, size_t sz) { ssize_t rc; int f; f = open("/dev/urandom", O_RDONLY); if (f == -1) return; rc = read(f, buf, sz); test_assert(rc == (ssize_t)sz, "%zi random bytes read", rc); close(f); } static void *recv_data_fec(void *arg) { uint8_t *buf = (uint8_t *)arg; ssize_t rc; lc_ctx_t *lctx = lc_ctx_new(); lc_socket_t * sock = lc_socket_new(lctx); lc_channel_t * chan = lc_channel_new(lctx, channel_name); memset(buf, 0, SZ); /* clear receive buffer */ lc_channel_bind(sock, chan); lc_channel_join(chan); lc_channel_coding_set(chan, LC_CODE_FEC_RQ); sem_post(&receiver_ready); rc = lc_channel_recv(chan, buf, SZ, 0); test_log("lc_channel_recv returned %zi\n", rc); test_assert(rc >= (ssize_t)SZ, "data received %zi/%zu bytes", rc, SZ); lc_channel_part(chan); lc_ctx_free(lctx); sem_post(&timeout); return arg; } static void *send_data_fec(void *arg) { uint8_t *buf = (uint8_t *)arg; lc_ctx_t *lctx = lc_ctx_new(); lc_socket_t * sock = lc_socket_new(lctx); lc_channel_t * chan = lc_channel_new(lctx, channel_name); rq_t *rq; ssize_t rc; size_t byt = 0; lc_socket_loop(sock, 1); lc_channel_bind(sock, chan); lc_channel_coding_set(chan, LC_CODE_FEC_RQ); test_log("sending data with FEC\n"); sem_wait(&receiver_ready); rc = lc_channel_send(chan, buf, SZ, 0); test_assert(rc > 0, "lc_channel_send encoded data, returned %zi", rc); if (rc == -1) goto err_ctx_free; byt = rc; rq = lc_channel_rq(chan); /* Send packets. Drop packet 3 */ int pkts = rq_KP(rq) + RQ_OVERHEAD * 2; test_log("sending %u packets\n", pkts); for (int i = 1; i < pkts; i++) { int flags = (i == 3) ? MSG_DROP : 0; rc = lc_channel_send(chan, NULL, 0, flags); test_assert(rc > 0, "lc_channel_send encoded data, returned %zi", rc); if (rc > 0) byt += rc; } test_assert(byt >= SZ, "data sent %zi bytes (buffer = %zu)", byt, SZ); err_ctx_free: lc_ctx_free(lctx); return arg; } #endif int main(void) { #ifndef HAVE_LIBLCRQ return test_skip("lc_channel_send() / lc_channel_recv() - RaptorQ (RFC 6330)"); #else pthread_t tid[2]; uint8_t *buf[2]; struct timespec ts; int rc; test_name("lc_channel_send() / lc_channel_recv() - RaptorQ (RFC 6330)"); test_require_net(TEST_NET_BASIC); buf[TID_SEND] = malloc(SZ); assert(buf[TID_SEND]); buf[TID_RECV] = malloc(SZ); assert(buf[TID_RECV]); memset(buf[0], 0, SZ); memset(buf[1], 0, SZ); sem_init(&timeout, 0, 0); sem_init(&receiver_ready, 0, 0); generate_source_data(buf[TID_SEND], SZ); test_assert(memcmp(buf[TID_RECV], buf[TID_SEND], SZ), "buffer differ before sync"); pthread_create(&tid[TID_SEND], NULL, &send_data_fec, buf[TID_SEND]); pthread_create(&tid[TID_RECV], NULL, &recv_data_fec, buf[TID_RECV]); clock_gettime(CLOCK_REALTIME, &ts); ts.tv_sec += WAITS; rc = sem_timedwait(&timeout, &ts); test_assert(rc == 0, "timeout"); pthread_cancel(tid[TID_RECV]); pthread_join(tid[TID_RECV], NULL); pthread_join(tid[TID_SEND], NULL); sem_destroy(&receiver_ready); sem_destroy(&timeout); if (!rc) test_assert(!memcmp(buf[TID_RECV], buf[TID_SEND], SZ), "send buffer matches received"); #ifdef TESTDEBUG dump_bufs(buf); #endif free(buf[TID_SEND]); free(buf[TID_RECV]); return test_status; #endif } librecast/test/0000-0040.c000066400000000000000000000117551502456746400151370ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2017-2024 Brett Sheffield */ #include "testnet.h" #include #include #include #include #include #include #include #include #include #undef TESTDEBUG #ifdef TESTDEBUG # define PKTS 10 # define PKTSZ 4 #else # define PKTS 20 # define PKTSZ 1024 #endif #define WAITS 20 #ifdef HAVE_LIBSODIUM #ifdef HAVE_LIBLCRQ enum { TID_SEND, TID_RECV }; static const size_t SZ = PKTS * PKTSZ + 5; static char channel_name[] = "0000-0040"; static sem_t receiver_ready, timeout; static int fec; static unsigned char key[crypto_secretbox_KEYBYTES]; #ifdef TESTDEBUG #if 0 static void dumppkt(uint8_t *pkt, int haseq) { uint16_t seq; uint8_t *dat = pkt; if (haseq) { dat += sizeof seq; seq = ntohs(*(uint16_t *)pkt); fprintf(stderr, "%u: ", seq); } else fprintf(stderr, " "); for (size_t z = 0; z < PKTSZ * 8; z++) { if (isset(dat, z)) putc('1', stderr); else putc('0', stderr); } putc('\n', stderr); } #endif static void dump_bufs(uint8_t buf[2][SZ]) { for (size_t p = 0; p < PKTS; p++) { fprintf(stderr, "%zu: ", p); for (int i = 0; i < 2; i++) { for (size_t z = 0; z < PKTSZ * 8; z++) { uint8_t *b = buf[i]; if (isset(b, p * PKTSZ * 8 + z)) putc('1', stderr); else putc('0', stderr); } putc(' ', stderr); } putc('\n', stderr); } putc('\n', stderr); } #endif static void generate_source_data(uint8_t *buf, size_t sz) { ssize_t rc; int f; f = open("/dev/urandom", O_RDONLY); if (f == -1) return; rc = read(f, buf, sz); test_assert(rc == (ssize_t)sz, "%zi random bytes read", rc); close(f); } static void *recv_data_fec(void *arg) { uint8_t *buf = (uint8_t *)arg; ssize_t rc; lc_ctx_t *lctx = lc_ctx_new(); lc_socket_t * sock = lc_socket_new(lctx); lc_channel_t * chan = lc_channel_new(lctx, channel_name); memset(buf, 0, SZ); /* clear receive buffer */ lc_channel_bind(sock, chan); lc_channel_join(chan); lc_channel_set_sym_key(chan, key, crypto_secretbox_KEYBYTES); lc_channel_coding_set(chan, LC_CODE_SYMM | LC_CODE_FEC_RQ); sem_post(&receiver_ready); rc = lc_channel_recv(chan, buf, SZ, 0); test_log("lc_channel_recv returned %zi\n", rc); test_assert(rc >= (ssize_t)SZ, "data received %zi/%zu bytes", rc, SZ); lc_channel_part(chan); lc_ctx_free(lctx); sem_post(&timeout); return arg; } static void *send_data_fec(void *arg) { uint8_t *buf = (uint8_t *)arg; lc_ctx_t *lctx; lc_socket_t *sock; lc_channel_t *chan; rq_t *rq; ssize_t rc; size_t byt = 0; lctx = lc_ctx_new(); pthread_cleanup_push((void (*)(void *))lc_ctx_free, lctx); sock = lc_socket_new(lctx); chan = lc_channel_new(lctx, channel_name); lc_socket_loop(sock, 1); lc_channel_bind(sock, chan); lc_channel_set_sym_key(chan, key, crypto_secretbox_KEYBYTES); lc_channel_coding_set(chan, LC_CODE_SYMM | LC_CODE_FEC_RQ); test_log("sending data with FEC + symmetric encryption\n"); sem_wait(&receiver_ready); rc = lc_channel_send(chan, buf, SZ, 0); test_assert(rc > 0, "lc_channel_send encoded data, returned %zi", rc); if (rc == -1) goto err_ctx_free; byt = rc; rq = lc_channel_rq(chan); /* Send packets. Drop packet 3 */ int pkts = rq_KP(rq) + RQ_OVERHEAD * 2; test_log("sending %u packets\n", pkts); for (int i = 1; i < pkts; i++) { int flags = (i == 3) ? MSG_DROP : 0; rc = lc_channel_send(chan, NULL, 0, flags); test_assert(rc > 0, "lc_channel_send encoded data, returned %zi", rc); if (rc > 0) byt += rc; } test_assert(byt >= SZ, "data sent %zi bytes (buffer = %zu)", byt, SZ); err_ctx_free: pthread_cleanup_pop(1); /* lc_ctx_free(lctx); */ return arg; } #endif #endif int main(void) { #if !defined(HAVE_LIBLCRQ) || !(HAVE_LIBSODIUM) return test_skip("lc_channel_send() / lc_socket_recv() - FEC + encrypt"); #else pthread_t tid[2]; uint8_t buf[2][SZ]; struct timespec ts; test_name("lc_channel_send() / lc_socket_recv() - FEC + encrypt"); test_require_net(TEST_NET_BASIC); /* run test twice */ for (fec = 0; fec < 2; fec++) { /* generate symmetric encryption key */ crypto_secretbox_keygen(key); /* clear buffers */ memset(buf[0], 0, SZ); memset(buf[1], 0, SZ); sem_init(&timeout, 0, 0); sem_init(&receiver_ready, 0, 0); generate_source_data(buf[TID_SEND], SZ); test_assert(memcmp(buf[TID_RECV], buf[TID_SEND], SZ), "buffer differ before sync"); pthread_create(&tid[TID_SEND], NULL, &send_data_fec, buf[TID_SEND]); pthread_create(&tid[TID_RECV], NULL, &recv_data_fec, buf[TID_RECV]); clock_gettime(CLOCK_REALTIME, &ts); ts.tv_sec += WAITS; test_assert(!sem_timedwait(&timeout, &ts), "timeout"); pthread_cancel(tid[TID_RECV]); pthread_join(tid[TID_RECV], NULL); pthread_cancel(tid[TID_SEND]); pthread_join(tid[TID_SEND], NULL); sem_destroy(&receiver_ready); sem_destroy(&timeout); test_assert(!memcmp(buf[TID_RECV], buf[TID_SEND], SZ), "send buffer matches received"); #ifdef TESTDEBUG dump_bufs(buf); #endif } return test_status; #endif } librecast/test/0000-0041.c000066400000000000000000000015601502456746400151310ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2017-2022 Brett Sheffield */ #include "test.h" #include #include #include #include int main(void) { char in[] = "hash browns"; unsigned char hash[2][HASHSIZE]; size_t len = strlen(in); int key = 1; test_name("hash_generic_key()"); hash_generic_key(hash[0], HASHSIZE, (unsigned char *)in, len, (unsigned char *)&key, sizeof(int)); hash_generic_key(hash[1], HASHSIZE, (unsigned char *)in, len, (unsigned char *)&key, sizeof(int)); test_assert(!memcmp(hash[0], hash[1], HASHSIZE), "hashes match"); /* now change key */ key++; hash_generic_key(hash[1], HASHSIZE, (unsigned char *)in, len, (unsigned char *)&key, sizeof(int)); test_assert(memcmp(hash[0], hash[1], HASHSIZE), "hashes differ"); return test_status; } librecast/test/0000-0042.c000066400000000000000000000101131502456746400151240ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2022 Claudio Calvelli */ #include "test.h" #include "testnet.h" #include #include #include #include #include #include #ifdef HAVE_ENDIAN_H #include #elif HAVE_SYS_ENDIAN_H #include #endif #include #define NUM_MESSAGES 10 static sem_t sem_nack, sem_main; static char channel_name[] = "0000-0042"; static int msg_seen = -1; static void *nack_thread(void * _logging) { lc_channel_logging_t * logging = _logging; lc_seq_t msg_expected = 1; pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); /* tell main() we have started */ sem_post(&sem_nack); while (1) { int ok = 0; pthread_testcancel(); /* wait for main() to send a message (the thread could be cancelled * while waiting and that's OK */ sem_wait(&sem_main); /* check that the message is in the queue; it will have the be the newest * because we know it's just been sent */ pthread_mutex_lock(&logging->mutex); if (logging->newest && logging->newest->seq == msg_expected) { /* check that the message is in fact what we expect it to be */ if (logging->newest->len >= sizeof(lc_message_head_t) + sizeof(int)) { lc_message_head_t head; memcpy(&head, logging->newest->data, sizeof(lc_message_head_t)); /* provisionally OK unless some of the checks below fail */ ok = 1; if (be64toh(head.seq) != msg_expected) ok = 0; if (be64toh(head.timestamp) != (uint64_t)msg_expected << 10) ok = 0; if (be64toh(head.len) != sizeof(int)) ok = 0; if (ok) { int data; char *ptr = logging->newest->data; memcpy(&data, &ptr[sizeof(lc_message_head_t)], sizeof(int)); if ((lc_seq_t)data != msg_expected) ok = 0; } } } pthread_mutex_unlock(&logging->mutex); if (ok) msg_seen = msg_expected; else msg_seen = -1; msg_expected++; /* let main() know we've done the checking */ sem_post(&sem_nack); } return NULL; } int main(void) { lc_ctx_t * lctx; lc_socket_t * sock; lc_channel_t * chan; lc_message_t message = { 0, }; int rc; test_name("Message logging for NACKs"); test_require_net(TEST_NET_BASIC); /* create a channel and enable the logging for the NACK thread, however instead * of using the normal NACK thread we provide one so that we can check what has * been logged */ lctx = lc_ctx_new(); if (!test_assert(lctx != NULL, "lc_ctx_new()")) return test_status; sock = lc_socket_new(lctx); if (!test_assert(sock != NULL, "lc_socket_new()")) goto err_ctx_free; chan = lc_channel_new(lctx, channel_name); if (!test_assert(chan != NULL, "lc_channel_new()")) goto err_ctx_free; rc = lc_channel_bind(sock, chan); if (!test_assert(rc == 0, "lc_channel_bind()")) goto err_ctx_free; rc = sem_init(&sem_main, 0, 0); if (!test_assert(rc == 0, "sem_init(sem_main) returned %i", rc)) goto err_ctx_free; rc = sem_init(&sem_nack, 0, 0); if (!test_assert(rc == 0, "sem_init(sem_nack) returned %i", rc)) goto err_sem_destroy_main; if (!test_assert(lc_channel_nack_handler_thr(chan, 10, nack_thread) >= 0, "Could not set up logging for NACKs")) goto err_sem_destroy_main; /* make sure the nack thread has started */ sem_wait(&sem_nack); /* now go and send a number of messages */ for (int msg_sent = 1; msg_sent <= NUM_MESSAGES; msg_sent++) { char description[64]; message.timestamp = (uint64_t)msg_sent << 10; message.seq = msg_sent; message.len = sizeof(msg_sent); message.data = &msg_sent; message.op = LC_OP_DATA; lc_msg_send(chan, &message); /* let the nack thread we have something for them */ sem_post(&sem_main); /* wait for them to look at it */ sem_wait(&sem_nack); /* and see if what we see is what we expect */ snprintf(description, sizeof(description), "Invalid message #%d saved for the NACK thread", msg_sent); test_assert(msg_seen == msg_sent, description); } sem_destroy(&sem_nack); err_sem_destroy_main: sem_destroy(&sem_main); err_ctx_free: lc_ctx_free(lctx); return test_status; } librecast/test/0000-0043.c000066400000000000000000000074541502456746400151430ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2022 Claudio Calvelli */ #include "testnet.h" #include #include #include #include #include #include #include #include #ifdef HAVE_ENDIAN_H #include #elif HAVE_SYS_ENDIAN_H #include #endif #define WAITS 1 #define NUM_MESSAGES 12 static sem_t sem; static char channel_name[] = "0000-0043"; static unsigned int msg_seen = 0; static const unsigned int msg_mask = (1U << NUM_MESSAGES) - 1; static void *recv_thread(void *arg) { unsigned int fail_it = (1U << 3) | (1U << 6); lc_ctx_t *lctx; lc_socket_t *sock_data, *sock_nack; lc_channel_t *chan_data, *chan_nack; (void)arg; /* create a channel to receive the messages */ lctx = lc_ctx_new(); sock_data = lc_socket_new(lctx); chan_data = lc_channel_new(lctx, channel_name); chan_nack = lc_channel_sidehash(chan_data, (void *)SIDE_CHANNEL_NACK, strlen(SIDE_CHANNEL_NACK)); sock_nack = lc_socket_new(lctx); lc_socket_loop(sock_nack, 1); lc_channel_bind(sock_data, chan_data); lc_channel_bind(sock_nack, chan_nack); lc_channel_join(chan_data); /* tell main() we have started */ msg_seen = 0; sem_post(&sem); while ((msg_seen & msg_mask) != msg_mask) { int num; lc_message_t message = { .data = (void *)&num, .len = sizeof(num), }; lc_msg_recv(sock_data, &message); /* is it the message we expected? */ if (message.seq >= 1 && message.seq <= NUM_MESSAGES && message.timestamp == (uint64_t)message.seq << 10) { unsigned int bit = 1U << (message.seq - 1); if (fail_it & bit) { /* pretend that we didn't receive this and send a NACK instead */ uint64_t miss = htobe64(message.seq); fail_it &= ~bit; lc_socket_send(sock_nack, &miss, sizeof(miss), 0); } else msg_seen |= bit; } lc_msg_free(&message); } /* tell main() that all is done here */ sem_post(&sem); lc_channel_free(chan_nack); lc_socket_close(sock_nack); lc_channel_free(chan_data); lc_socket_close(sock_data); lc_ctx_free(lctx); return NULL; } int main(void) { lc_ctx_t * lctx; lc_socket_t * sock; lc_channel_t * chan; lc_message_t message = {0}; pthread_t rthread; pthread_attr_t attr; struct timespec ts; test_name("NACK 1: retransmission of packet received but discarded"); test_require_net(TEST_NET_BASIC); /* create a channel and enable the logging with the standard NACK thread */ lctx = lc_ctx_new(); sock = lc_socket_new(lctx); chan = lc_channel_new(lctx, channel_name); lc_socket_loop(sock, 1); lc_channel_bind(sock, chan); sem_init(&sem, 0, 0); test_assert(lc_channel_nack_handler(chan, 10) >= 0, "Could not set NACK hread"); /* get ready... */ pthread_attr_init(&attr); pthread_create(&rthread, &attr, recv_thread, NULL); pthread_attr_destroy(&attr); /* make sure the recv thread has started */ sem_wait(&sem); /* now go and send a number of messages */ for (int msg_sent = 1; msg_sent <= NUM_MESSAGES; msg_sent++) { message.timestamp = (uint64_t)msg_sent << 10; message.seq = msg_sent; message.len = sizeof(msg_sent); message.data = &msg_sent; message.op = LC_OP_DATA; lc_msg_send(chan, &message); } /* wait for the receive thread to have received everything */ clock_gettime(CLOCK_REALTIME, &ts); ts.tv_sec += WAITS; sem_timedwait(&sem, &ts); pthread_cancel(rthread); pthread_join(rthread, NULL); /* check we've received all messages */ for (int msg_num = 0; msg_num < NUM_MESSAGES; msg_num++) { char description[64]; snprintf(description, sizeof(description), "Message #%d not received from NACK thread", msg_num); test_assert(msg_seen & (1U << msg_num), description); } lc_channel_free(chan); lc_socket_close(sock); lc_ctx_free(lctx); sem_destroy(&sem); return test_status; } librecast/test/0000-0044.c000066400000000000000000000107521502456746400151370ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2022 Claudio Calvelli */ #include "testnet.h" #include #include #include #include #include #include #include #include #ifdef HAVE_ENDIAN_H #include #elif HAVE_SYS_ENDIAN_H #include #endif #define WAITS 1 #define NUM_MESSAGES 12 static sem_t sem; static char channel_name[] = "0000-0044"; static unsigned int msg_seen = 0; static const unsigned int msg_mask = (1U << NUM_MESSAGES) - 1; static pthread_mutex_t send_mutex = PTHREAD_MUTEX_INITIALIZER; static void send_message(lc_channel_t * chan, int seqno) { lc_message_t message = {0}; message.timestamp = (uint64_t)seqno << 10; message.seq = seqno; message.len = sizeof(seqno); message.data = &seqno; message.op = LC_OP_DATA; pthread_mutex_lock(&send_mutex); /* fake seqno... */ chan->seq = seqno - 1; lc_msg_send(chan, &message); pthread_mutex_unlock(&send_mutex); } static void *nack_thread(void * _logging) { lc_channel_logging_t * logging = _logging; pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); while (1) { /* wait for a NACK packet if one is arriving */ uint64_t nack; lc_seq_t seq; pthread_testcancel(); if (lc_socket_recv(logging->sock_nack, &nack, sizeof(nack), 0) == -1) break; seq = be64toh(nack); if (seq < 1 || seq > 16) continue; /* send the packet - note that we know it won't have been logged because * we simulated packet loss by not sending so we cannot use the standard * nack thread, and we won't find it in the logged data */ send_message(logging->chan_data, seq); } return NULL; } static void *recv_thread(void *arg) { lc_ctx_t *lctx; lc_socket_t *sock; lc_channel_t *chan; (void)arg; /* create a channel to receive the messages */ lctx = lc_ctx_new(); sock = lc_socket_new(lctx); chan = lc_channel_new(lctx, channel_name); lc_socket_loop(sock, 1); lc_channel_bind(sock, chan); lc_channel_join(chan); lc_channel_detect_gaps(chan); /* tell main() we have started */ msg_seen = 0; sem_post(&sem); while ((msg_seen & msg_mask) != msg_mask) { int num; lc_message_t message = { .data = (void *)&num, .len = sizeof(num), }; lc_msg_recv(sock, &message); /* is it the message we expected? */ if (message.seq >= 1 && message.seq <= NUM_MESSAGES && message.timestamp == (uint64_t)message.seq << 10) msg_seen |= 1U << (message.seq - 1); lc_msg_free(&message); } lc_channel_free(chan); lc_socket_close(sock); lc_ctx_free(lctx); /* tell main() that all is done here */ sem_post(&sem); return NULL; } int main(void) { lc_ctx_t * lctx; lc_socket_t * sock; lc_channel_t * chan; pthread_t rthread; pthread_attr_t attr; struct timespec ts; test_name("NACK 2: retransmission after simulated packet loss"); test_require_net(TEST_NET_BASIC); /* create a channel and enable the logging for the NACK thread, however instead * of using the normal NACK thread we provide one that generates replay messages * in the same way as they would be generated; then we test gap detection by * omitting a few packets when sending, to simulate packet loss */ lctx = lc_ctx_new(); sock = lc_socket_new(lctx); chan = lc_channel_new(lctx, channel_name); lc_socket_loop(sock, 1); lc_channel_bind(sock, chan); sem_init(&sem, 0, 0); test_assert(lc_channel_nack_handler_thr(chan, 10, nack_thread) >= 0, "Could not set up NACK thread"); /* get ready... */ pthread_attr_init(&attr); pthread_create(&rthread, &attr, recv_thread, NULL); pthread_attr_destroy(&attr); /* make sure the recv thread has started */ sem_wait(&sem); /* now go and send a number of messages, skipping 2 */ for (int msg_sent = 1; msg_sent <= NUM_MESSAGES; msg_sent++) if (msg_sent != 4 && msg_sent != 7) send_message(chan, msg_sent); /* wait for the receive thread to have received everything */ clock_gettime(CLOCK_REALTIME, &ts); ts.tv_sec += WAITS; sem_timedwait(&sem, &ts); pthread_cancel(rthread); pthread_join(rthread, NULL); /* check we've received all messages */ for (int msg_num = 0; msg_num < NUM_MESSAGES; msg_num++) { char description[64]; snprintf(description, sizeof(description), "Message #%d not received from NACK thread", msg_num + 1); test_assert(msg_seen & (1U << msg_num), description); } lc_channel_free(chan); lc_socket_close(sock); lc_ctx_free(lctx); sem_destroy(&sem); return test_status; } librecast/test/0000-0045.c000066400000000000000000000056631502456746400151450ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2017-2023 Brett Sheffield */ #include "testnet.h" #include #include #include #include #include #include #include #include #include #include #define SZ PKTS * PKTSZ + 5 #define WAITS 1 #ifdef HAVE_RQ_OTI enum { TID_SEND, TID_RECV }; struct oti_header { rq_oti_t oti; rq_scheme_t scheme; }; static char channel_name[] = "0000-0045"; static sem_t receiver_ready, timeout; static void *recv_oti(void *arg) { struct oti_header *oti = (struct oti_header *)arg; lc_ctx_t *lctx = lc_ctx_new(); lc_socket_t * sock = lc_socket_new(lctx); lc_channel_t * chan = lc_channel_new(lctx, channel_name); lc_channel_bind(sock, chan); lc_channel_join(chan); lc_channel_coding_set(chan, LC_CODE_FEC_RQ | LC_CODE_FEC_OTI); sem_post(&receiver_ready); lc_channel_oti_peek(chan, &oti->oti, &oti->scheme); lc_channel_part(chan); lc_ctx_free(lctx); sem_post(&timeout); return arg; } static void *send_oti(void *arg) { struct oti_header *oti = (struct oti_header *)arg; lc_ctx_t *lctx = lc_ctx_new(); lc_socket_t * sock = lc_socket_new(lctx); lc_channel_t * chan = lc_channel_new(lctx, channel_name); char buf[] = "Celebrating Pride Month June 2023: LGBTQ++"; lc_socket_loop(sock, 1); lc_channel_bind(sock, chan); sem_wait(&receiver_ready); test_log("sending data with OTI header"); lc_channel_coding_set(chan, LC_CODE_FEC_RQ | LC_CODE_FEC_OTI); lc_channel_send(chan, buf, sizeof buf, 0); rq_oti(lc_channel_rq(chan), &oti->oti, &oti->scheme); for (uint16_t i = 0; i < 100 + 5; i++) { lc_channel_send(chan, NULL, 0, 0); } lc_ctx_free(lctx); return arg; } #endif int main(void) { char name[] = "RaptorQ FEC Object Transmission Information"; #ifndef HAVE_RQ_OTI return test_skip(name); #else pthread_t tid[2]; struct oti_header oti[2]; struct timespec ts; test_name(name); test_require_net(TEST_NET_BASIC); oti[0].oti = 1; oti[1].oti = 2; oti[0].scheme = 1; oti[1].scheme = 2; test_assert(oti[TID_SEND].oti != oti[TID_RECV].oti, "OTI (common) differ before test"); test_assert(oti[TID_SEND].scheme != oti[TID_RECV].scheme, "OTI (scheme) differ before test"); sem_init(&timeout, 0, 0); sem_init(&receiver_ready, 0, 0); pthread_create(&tid[TID_SEND], NULL, &send_oti, &oti[TID_SEND]); pthread_create(&tid[TID_RECV], NULL, &recv_oti, &oti[TID_RECV]); clock_gettime(CLOCK_REALTIME, &ts); ts.tv_sec += WAITS; test_assert(!sem_timedwait(&timeout, &ts), "timeout"); pthread_cancel(tid[TID_RECV]); pthread_join(tid[TID_RECV], NULL); pthread_join(tid[TID_SEND], NULL); sem_destroy(&receiver_ready); sem_destroy(&timeout); test_assert(oti[TID_SEND].oti == oti[TID_RECV].oti, "OTI (common) matches"); test_assert(oti[TID_SEND].scheme == oti[TID_RECV].scheme, "OTI (scheme) matches"); return test_status; #endif } librecast/test/0000-0046.c000066400000000000000000000105101502456746400151310ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2023 Brett Sheffield */ #include "test.h" #include "testdata.h" #include #include #include int main(void) { unsigned char hash[HASHSIZE]; char hex[HEXLEN]; mdex_t *mdex; mdex_entry_t entry = {0}; const size_t entries = 64; char *path; mdex_filemeta_t file = {0}; size_t z; int rc; test_name("Channel Indexing - mdex_*()"); path = strdup("/path/to/file/that/will/be/reused"); file.name = path; /* create an mdex and fill it will entries */ mdex = mdex_init(entries); for (z = 0; z < entries + 1; z++) { hash_generic(hash, HASHSIZE, (unsigned char *)&z, sizeof z); hash_bin2hex(hex, sizeof hex, hash, sizeof hash); fprintf(stderr, "%zu: %s\n", z, hex); /* entry */ entry.type = ((char)z & 1) + 1; /* odd => MDEX_FILE, even => MDEX_PTR */ entry.ptr.size = z; switch (entry.type) { case MDEX_PTR: entry.ptr.data = (void *)0x1234; break; case MDEX_FILE: entry.file.off = z; entry.file.file = file; break; } errno = 0; rc = mdex_get(mdex, hash, HASHSIZE, NULL); test_assert(rc == -1, "entry %zu not found before adding", z); test_assert(errno == ENOENT, "entry %zu errno == ENOENT", z); rc = mdex_put(mdex, hash, HASHSIZE, &entry); test_assert(rc == 0, "entry %zu added", z); rc = mdex_get(mdex, hash, HASHSIZE, NULL); test_assert(rc == 0, "entry %zu found after adding", z); } for (z = 0; z < entries; z++) { /* check each entry */ hash_generic(hash, HASHSIZE, (unsigned char *)&z, sizeof z); hash_bin2hex(hex, sizeof hex, hash, sizeof hash); fprintf(stderr, "%zu: %s\n", z, hex); rc = mdex_get(mdex, hash, HASHSIZE, &entry); test_assert(rc == 0, "entry %zu found", z); test_assert(entry.type == ((char)z & 1) + 1, "entry type %i", entry.type); test_assert(entry.ptr.size == z, "entry size set"); switch (entry.type) { case MDEX_PTR: test_assert(entry.ptr.data == (void *)0x1234, "entry (PTR) data ptr set"); break; case MDEX_FILE: test_assert(entry.file.off == z, "entry (FILE) off set"); test_assert(!strcmp(entry.file.file.name, path), "entry file name set"); break; } } /* delete entry, check it was removed */ #define deleteme 11 z = deleteme; hash_generic(hash, HASHSIZE, (unsigned char *)&z, sizeof z); rc = mdex_del(mdex, hash, HASHSIZE); test_assert(rc == 0, "%zu: mdex_del returned %i", z, rc); rc = mdex_get(mdex, hash, HASHSIZE, NULL); test_assert(rc == -1, "entry %zu not found after deleting", z); test_assert(errno == ENOENT, "entry %zu errno == ENOENT", z); /* check other entries are still reachable */ for (z = 0; z < entries; z++) { if (z == deleteme) continue; /* check each entry */ hash_generic(hash, HASHSIZE, (unsigned char *)&z, sizeof z); rc = mdex_get(mdex, hash, HASHSIZE, NULL); test_assert(rc == 0, "entry %zu found", z); } /* delete root node */ z = 0; hash_generic(hash, HASHSIZE, (unsigned char *)&z, sizeof z); rc = mdex_del(mdex, hash, HASHSIZE); test_assert(rc == 0, "%zu: mdex_del returned %i", z, rc); rc = mdex_get(mdex, hash, HASHSIZE, NULL); test_assert(rc == -1, "entry %zu not found after deleting", z); test_assert(errno == ENOENT, "entry %zu errno == ENOENT", z); /* check other entries are still reachable */ for (z = 1; z < entries; z++) { if (z == deleteme) continue; /* check each entry */ hash_generic(hash, HASHSIZE, (unsigned char *)&z, sizeof z); rc = mdex_get(mdex, hash, HASHSIZE, NULL); test_assert(rc == 0, "entry %zu found (after root deletion)", z); } /* add a new entry, reusing deleted entry from stack */ mdex_entry_t reentry = {0}; z = entries + 1; entry.type = CHAR_MAX; hash_generic(hash, HASHSIZE, (unsigned char *)&z, sizeof z); rc = mdex_put(mdex, hash, HASHSIZE, &entry); test_assert(rc == 0, "entry %zu added", z); rc = mdex_get(mdex, hash, HASHSIZE, &reentry); test_assert(rc == 0, "entry %zu found after adding", z); /* update previously added entry */ entry.type = 42; rc = mdex_put(mdex, hash, HASHSIZE, &entry); test_assert(rc == 0, "entry %zu added", z); rc = mdex_get(mdex, hash, HASHSIZE, &reentry); test_assert(rc == 0, "entry %zu found after adding", z); test_assert(reentry.type == 42, "entry was updated %i == %i", (int)entry.type, (int)reentry.type); mdex_free(mdex); return test_status; } librecast/test/0000-0047.c000066400000000000000000000017111502456746400151350ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2023-2024 Brett Sheffield */ #include "test.h" #include "testdata.h" #include #include #include static mdex_stack_t stack; #include int main(void) { void * testptr = (void *)0xcafe; void * ret; test_name("mdex_stack_push() / mdex_stack_pop()"); test_assert(mdex_stack_pop(&stack) == NULL, "mdex_stack_pop() with empty stack => NULL"); /* push some entries onto the stack */ for (int i = 0; i < MDEX_STACK_SZ; i++) { mdex_stack_push(&stack, (char *)testptr + i); } /* pop them back again */ for (int i = MDEX_STACK_SZ - 1; i > -1; i--) { ret = mdex_stack_pop(&stack); test_assert(ret == (char *)testptr + i, "push and pop returned %p", ret); } test_assert(mdex_stack_pop(&stack) == NULL, "mdex_stack_pop() with empty stack => NULL"); free(stack.stack); return test_status; } librecast/test/0000-0048.c000066400000000000000000000024051502456746400151370ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2023 Brett Sheffield */ #include "test.h" #include "testdata.h" #include #include #define GRPBYTES 14 /* bytes for multicast group */ /* we need to be able to match an expected channel hash to the lower 14 bytes of * the address for MLD triggers etc. Ensure this isn't mangled */ int main(void) { unsigned char rand[1024]; unsigned char hash1[HASHSIZE]; unsigned char hash2[HASHSIZE]; lc_ctx_t *lctx; lc_channel_t *chan; struct in6_addr *addr; test_name("lc_channel_nnew(): ensure lower 14 bytes of address match hash"); test_random_bytes(rand, sizeof rand); /* if we ask for fewer bytes from our hash function, this is just * the full hash truncated */ hash_generic(hash1, HASHSIZE, rand, sizeof rand); hash_generic(hash2, GRPBYTES, rand, sizeof rand); test_assert(!memcmp(hash1, hash2, GRPBYTES), "ensure our hash function truncates hashes predictably"); /* ensure hash can be recreated */ lctx = lc_ctx_new(); chan = lc_channel_nnew(lctx, rand, sizeof rand); addr = lc_channel_in6addr(chan); test_assert(!memcmp(hash1, &addr->s6_addr[2], GRPBYTES), "address matches hash"); lc_ctx_free(lctx); return test_status; } librecast/test/0000-0049.c000066400000000000000000000015061502456746400151410ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2023 Brett Sheffield */ #include "test.h" #include "testdata.h" #include #include #include int main(void) { mdex_t *mdex; unsigned char rand[123]; unsigned char hash[HASHSIZE]; int rc; test_name("mdex_get() find entry with truncated hash"); mdex = mdex_init(1); test_random_bytes(rand, sizeof rand); hash_generic(hash, HASHSIZE, rand, sizeof rand); rc = mdex_get(mdex, hash, HASHSIZE, NULL); test_assert(rc == -1, "entry not found before adding"); rc = mdex_put(mdex, hash, HASHSIZE, NULL); test_assert(rc == 0, "entry added"); rc = mdex_get(mdex, hash, 14, NULL); test_assert(rc == 0, "entry found using truncated hash"); mdex_free(mdex); return test_status; } librecast/test/0000-0050.c000066400000000000000000000044111502456746400151270ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2023 Brett Sheffield */ #include "test.h" #include "testdata.h" #include #include #include int main(void) { unsigned char hash[HASHSIZE]; unsigned char alias[HASHSIZE]; mdex_t *mdex; mdex_entry_t entry = {0}; const size_t entries = 64; size_t z; int rc; test_name("mdex_get() find aliased entry"); /* create index and some entries */ mdex = mdex_init(entries); entry.type = MDEX_PTR; for (size_t i = 0; i < entries; i++) { hash_generic(hash, sizeof hash, (unsigned char *)&i, sizeof i); entry.ptr.size = sizeof i; entry.ptr.data = (void *)i; rc = mdex_put(mdex, hash, sizeof hash, &entry); test_assert(rc == 0, "mdex_put() returned %i (entry %i)", rc, i); } /* try to fetch entry that doesn't exist */ rc = entries + 1; hash_generic(hash, sizeof hash, (unsigned char *)&rc, sizeof rc); rc = mdex_get(mdex, hash, sizeof hash, &entry); test_assert(rc == -1, "mdex_get() returned %i (entry doesn't exist)"); test_assert(errno == ENOENT, "try to fetch entry that doesn't exist"); /* verify the entries we did write are correct */ for (size_t i = 0; i < entries; i++) { hash_generic(hash, sizeof hash, (unsigned char *)&i, sizeof i); memset(&entry, 0, sizeof entry); rc = mdex_get(mdex, hash, sizeof hash, &entry); test_assert(rc == 0, "mdex_get() returned %i (entry %i)", rc, i); test_assert((size_t)entry.ptr.data == i, "data matches (%i)", i); } /* write an alias entry (65), pointing to entry 42 */ z = entries + 1; hash_generic(hash, sizeof hash, (unsigned char *)&z, sizeof z); z = 42; hash_generic(alias, sizeof alias, (unsigned char *)&z, sizeof z); rc = mdex_alias(mdex, hash, sizeof hash, alias, sizeof alias); test_assert(rc == 0, "mdex_alias() returned %i", rc); perror("mdex_alias"); memset(&entry, 0, sizeof entry); rc = mdex_get(mdex, hash, sizeof hash, &entry); test_assert(rc == 0, "mdex_get() returned %i (fetching alias)", rc); /* alias entry retrieved should be that of the entry it points to */ test_assert(entry.ptr.size == sizeof(size_t), "entry size correct"); test_assert((size_t)entry.ptr.data == 42, "alias fetched correct entry"); mdex_free(mdex); return test_status; } librecast/test/0000-0051.c000066400000000000000000000033341502456746400151330ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2023 Brett Sheffield */ #include "test.h" #include "testdata.h" #include #include #include int main(void) { mdex_t *mdex; unsigned char rand[123]; unsigned char hash[HASHSIZE]; int rc; test_name("mdex_*() return EINVAL when arguments invalid"); test_random_bytes(rand, sizeof rand); hash_generic(hash, HASHSIZE, rand, sizeof rand); /* mdex required for put/get/del */ errno = 0; rc = mdex_put(NULL, hash, HASHSIZE, NULL); test_assert(rc == -1, "mdex_put() requires mdex_t"); test_assert(errno == EINVAL, "errno == EINVAL"); errno = 0; rc = mdex_get(NULL, hash, HASHSIZE, NULL); test_assert(rc == -1, "mdex_get() requires mdex_t"); test_assert(errno == EINVAL, "errno == EINVAL"); errno = 0; rc = mdex_del(NULL, hash, HASHSIZE); test_assert(rc == -1, "mdex_del() requires mdex_t"); test_assert(errno == EINVAL, "errno == EINVAL"); mdex = mdex_init(1); /* hash and hashlen > 0 required for put/get/del */ errno = 0; rc = mdex_put(mdex, NULL, HASHSIZE, NULL); test_assert(rc == -1, "mdex_put() requires hash"); errno = 0; rc = mdex_put(mdex, hash, 0, NULL); test_assert(rc == -1, "mdex_put() requires hashlen"); errno = 0; rc = mdex_get(mdex, NULL, HASHSIZE, NULL); test_assert(rc == -1, "mdex_get() requires hash"); errno = 0; rc = mdex_get(mdex, hash, 0, NULL); test_assert(rc == -1, "mdex_get() requires hashlen"); errno = 0; rc = mdex_del(mdex, NULL, HASHSIZE); test_assert(rc == -1, "mdex_del() requires hash"); errno = 0; rc = mdex_del(mdex, hash, 0); test_assert(rc == -1, "mdex_del() requires hashlen"); mdex_free(mdex); return test_status; } librecast/test/0000-0052.c000066400000000000000000000112151502456746400151310ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2023-2024 Brett Sheffield */ #include "testdata.h" #include "testnet.h" #include #include #include #include #include #include #include #define TEST_SIZE 1024 * 100 + 5 /* nice powers of two hide bugs - ensure test size is odd */ _Static_assert(TEST_SIZE % 2, "TEST_SIZE must be an odd number"); #define TIMEOUT_SECONDS 10 #ifdef HAVE_RQ_OTI # ifdef HAVE_MLD enum { TID_SEND, TID_RECV }; static sem_t sem_recv; static sem_t sem_send; struct pkg_s { void *data; size_t len; uint8_t *hash; }; /* wrapper for pthread_cleanup_push */ inline static void _lc_channel_part(lc_channel_t *chan) { (void)lc_channel_part(chan); } void *thread_recv(void *arg) { struct pkg_s *pkg = (struct pkg_s *)arg; lc_ctx_t *lctx; lc_socket_t *sock; lc_channel_t *chan; lctx = lc_ctx_new(); pthread_cleanup_push((void (*)(void *))lc_ctx_free, lctx); sock = lc_socket_new(lctx); pthread_cleanup_push((void (*)(void *))lc_socket_close, sock); chan = lc_channel_hash(lctx, pkg->hash, HASHSIZE, LC_DEFAULT_FLAGS, LC_DEFAULT_PORT); pthread_cleanup_push((void (*)(void *))lc_channel_free, chan); char straddr[INET6_ADDRSTRLEN]; inet_ntop(AF_INET6, lc_channel_in6addr(chan), straddr, INET6_ADDRSTRLEN); fprintf(stderr, "joining %s\n", straddr); sem_wait(&sem_send); /* wait until sender is ready */ lc_channel_bind(sock, chan); lc_channel_coding_set(chan, LC_CODE_FEC_RQ); lc_channel_join(chan); pthread_cleanup_push((void (*)(void *))_lc_channel_part, chan); lc_channel_recv(chan, pkg->data, pkg->len, 0); pthread_cleanup_pop(1); /* lc_channel_part */ pthread_cleanup_pop(1); /* lc_channel_free */ pthread_cleanup_pop(1); /* lc_socket_close */ pthread_cleanup_pop(1); /* lc_ctx_free */ sem_post(&sem_recv); return NULL; } void *thread_send(void *arg) { struct pkg_s *pkg = (struct pkg_s *)arg; lc_ctx_t *lctx; lc_share_t *share; mdex_t *mdex; mdex_entry_t entry = {0}; int rc; lctx = lc_ctx_new(); pthread_cleanup_push((void (*)(void *))lc_ctx_free, lctx); /* build mdex */ mdex = mdex_init(1); pthread_cleanup_push((void (*)(void *))mdex_free, mdex); entry.type = MDEX_PTR; entry.ptr.data = pkg->data; entry.ptr.size = pkg->len; rc = mdex_put(mdex, pkg->hash, HASHSIZE, &entry); test_assert(rc == 0, "entry added"); /* share data */ share = lc_share(lctx, mdex, 0, NULL, NULL, LC_SHARE_LOOPBACK); pthread_cleanup_push((void (*)(void *))lc_unshare, share); test_assert(share != NULL, "lc_share()"); sem_post(&sem_send); /* tell recv thread we're ready */ pause(); pthread_cleanup_pop(1); /* lc_unshare(share) */ pthread_cleanup_pop(1); /* mdex_free(mdex) */ pthread_cleanup_pop(1); /* lc_ctx_free(lctx) */ return NULL; } # endif /* HAVE_MLD */ #endif /* HAVE_RQ_OTI */ int main(void) { #if defined HAVE_RQ_OTI && defined HAVE_MLD pthread_t tid[2]; struct pkg_s pkg_send = {0}, pkg_recv = {0}; struct timespec timeout = {0}; uint8_t *src, *dst; unsigned char hash[HASHSIZE]; test_cap_require(CAP_NET_ADMIN); test_name("lc_share() / lc_unshare()"); test_require_net(TEST_NET_BASIC); /* allocate some memory to work with */ src = malloc(TEST_SIZE); test_assert(src != NULL, "allocate source"); if (!src) return TEST_FAIL; dst = malloc(TEST_SIZE); memset(dst, 0, TEST_SIZE); test_assert(dst != NULL, "allocate destination"); if (!dst) return TEST_FAIL; test_assert(!test_random_bytes(src, TEST_SIZE), "randomize src"); test_assert(memcmp(dst, src, TEST_SIZE), "dst and src differ"); hash_generic(hash, HASHSIZE, src, sizeof src); /* start send thread */ sem_init(&sem_send, 0, 0); pkg_send.data = src; pkg_send.len = TEST_SIZE; pkg_send.hash = hash; pthread_create(&tid[TID_SEND], NULL, thread_send, &pkg_send); /* start recv thread */ sem_init(&sem_recv, 0, 0); pkg_recv.data = dst; pkg_recv.len = TEST_SIZE; pkg_recv.hash = hash; pthread_create(&tid[TID_RECV], NULL, thread_recv, &pkg_recv); /* handle timeout */ clock_gettime(CLOCK_REALTIME, &timeout); timeout.tv_sec += TIMEOUT_SECONDS; int ret; if ((ret = sem_timedwait(&sem_recv, &timeout)) == -1 && errno == ETIMEDOUT) { for (int i = 0; i < 2; i++) pthread_cancel(tid[i]); } pthread_cancel(tid[TID_SEND]); test_assert(ret == 0, "timeout waiting for recv thread"); sem_destroy(&sem_recv); sem_destroy(&sem_send); /* stop threads */ for (int i = 0; i < 2; i++) pthread_join(tid[i], NULL); /* check what we received */ test_assert(!memcmp(dst, src, TEST_SIZE), "dst matches src"); free(dst); free(src); return test_status; #else return test_skip("MLD/LCRQ not enabled"); #endif } librecast/test/0000-0053.c000066400000000000000000000074251502456746400151420ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2023 Brett Sheffield */ #include "test.h" #include "testdata.h" #include #include #include int runtest_size(size_t TEST_SIZE) { net_tree_t *nettree; unsigned char treehash[HASHSIZE] = {0}; unsigned char *testdata; unsigned char *hash; uint8_t *ptr; mdex_t *mdex; mtree_t mtree = {0}; mtree_t newtree = {0}; mdex_entry_t entry = {0}; size_t chunksz, hashsz, min, max, parts, sz; size_t off = 0; size_t len = TEST_SIZE; int rc; testdata = malloc(TEST_SIZE); assert(testdata); test_random_bytes(testdata, TEST_SIZE); mdex = mdex_init(0); rc = mtree_init(&mtree, TEST_SIZE); test_assert(rc == 0, "mtree_init() returned %i", rc); rc = mtree_build(&mtree, testdata, NULL); test_assert(rc == 0, "mtree_build() returned %i", rc); rc = mdex_add(mdex, testdata, TEST_SIZE, NULL, 0); test_assert(rc == 0, "mdex_add() returned %i", rc); hashsz = HASHSIZE * mtree.nodes; /* test root hash of mtree + all chunks are in index */ rc = mtree_init(&newtree, TEST_SIZE); ptr = newtree.tree; test_assert(rc == 0, "mtree_init(newtree) returned %i", rc); /* check all parts of tree are in mdex */ sz = sizeof (net_tree_t) + hashsz; parts = howmany(sz, MTREE_CHUNKSIZE); fprintf(stderr, "tree has %zu parts\n", parts); for (size_t z = 0; z < parts; z++) { mdex_tree_hash(treehash, HASHSIZE, &mtree, z); fprintf(stderr, "%zu: ", z); hash_hex_debug(stderr, treehash, HASHSIZE); rc = mdex_get(mdex, treehash, HASHSIZE, &entry); test_assert(rc == 0, "root hash found"); if (rc != 0) goto exit_0; fprintf(stderr, "sizeof(struct net_tree_s)=%zu\n", sizeof(struct net_tree_s)); off = (z) ? 0 : offsetof(net_tree_t, tree); /* skip to tree on first part */ fprintf(stderr, "%zu: off = %zu\n", z, off); fprintf(stderr, "copying %zu bytes of tree\n", entry.ptr.size - off); memcpy(ptr, (uint8_t *)entry.ptr.data + off, entry.ptr.size - off); ptr += entry.ptr.size - off; chunksz = MIN(sz, MTREE_CHUNKSIZE); test_assert(entry.type == (MDEX_PTR | MDEX_OTI), "root entry type set, %i", entry.type); test_assert(entry.ptr.size == chunksz, "root entry size set, sz=%zu, expected %zu", entry.ptr.size, chunksz); nettree = (net_tree_t *)entry.ptr.data; if (!z) test_assert(be64toh(nettree->size) == mtree.len, "tree size set"); sz -= MTREE_CHUNKSIZE; } /* test reassembled tree */ test_assert(newtree.len == mtree.len, "len = %zu", newtree.len); test_assert(newtree.base == mtree.base, "base = %zu", newtree.base); test_assert(newtree.chunks == mtree.chunks, "chunks = %zu", newtree.chunks); test_assert(newtree.nodes == mtree.nodes, "nodes = %zu", newtree.nodes); test_assert(mtree_verify(&newtree) == 0, "reassembled tree is valid"); test_assert(!memcmp(newtree.tree, mtree.tree, hashsz), "reassembled tree matches"); min = mtree_subtree_data_min(mtree.base, 0); max = min + mtree.chunks - 1; off = 0; for (size_t z = min; z <= max; z++) { hash = mtree_nnode(&mtree, z); fprintf(stderr, "%03zu: ", z); hash_hex_debug(stderr, hash, HASHSIZE); assert(hash); rc = mdex_get(mdex, hash, HASHSIZE, &entry); test_assert(rc == 0, "hash %zu found", z); test_assert(entry.ptr.size == MIN(MTREE_CHUNKSIZE, len), "size %zu matches", z); test_assert(entry.ptr.data == testdata + off, "entry %zu matches", z); off += MTREE_CHUNKSIZE; len -= MTREE_CHUNKSIZE; } exit_0: mtree_free(&newtree); mtree_free(&mtree); mdex_free(mdex); free(testdata); return test_status; } int main(void) { test_name("mdex_add()"); runtest_size(1024 * 31 + 5); /* single node */ runtest_size(1024 * 100 + 5); runtest_size(1024 * 1024 + 5); /* larger tree with padding chunks */ runtest_size(1024 * 1024 * 32 + 5); /* multi-part tree */ return test_status; } librecast/test/0000-0054.c000066400000000000000000000062021502456746400151330ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2023 Brett Sheffield */ #include "test.h" #include "testdata.h" #include #include #include #define TEST_SIZE 1024 * 1024 + 5 /* nice powers of two hide bugs - ensure test size is odd */ static_assert(TEST_SIZE % 2, "TEST_SIZE must be an odd number"); int main(void) { struct stat sb; char src[] = "0000-0054.src.tmp.XXXXXX"; unsigned char alias[HASHSIZE]; unsigned char *hash; unsigned char *testdata; mdex_t *mdex; mtree_t mtree = {0}; net_tree_t *nettree; mdex_entry_t entry = {0}; size_t min, max; size_t off = 0; size_t sz = 0; size_t len = TEST_SIZE; int fds, rc; test_name("mdex_addfile()"); /* create test file */ fds = test_data_file(src, TEST_SIZE, TEST_TMP | TEST_RND); test_assert(fds != -1, "test_data_file()"); if (fds == -1) goto exit_0; test_assert(test_data_size(src, TEST_SIZE) == 0, "source exists and is correct size"); test_assert(stat(src, &sb) != -1, "stat source file"); mdex = mdex_init(0); rc = mtree_init(&mtree, TEST_SIZE); test_assert(rc == 0, "mtree_init() returned %i", rc); /* map file, build tree */ testdata = lc_mmapfile(src, &sz, PROT_READ, MAP_PRIVATE, 0, &sb); rc = mtree_build(&mtree, testdata, NULL); rc = mdex_addfile(mdex, src, NULL, MDEX_ALIAS); test_assert(rc == 0, "mdex_addfile() returned %i", rc); /* test root hash of mtree + all chunks are in index */ mdex_tree_hash_sb(alias, sizeof alias, &mtree, 0, &sb, src); test_log("fetching root hash\n"); hash_hex_debug(stderr, alias, HASHSIZE); rc = mdex_get(mdex, alias, HASHSIZE, &entry); test_assert(rc == 0, "root hash found"); test_assert((entry.type & (MDEX_PTR | MDEX_OTI)), "root entry type set"); nettree = (net_tree_t *)entry.ptr.data; nettree->namesz = ntohs(nettree->namesz); sz = sizeof (net_tree_t) + HASHSIZE * mtree.nodes + nettree->namesz; test_assert(entry.ptr.size == sz, "root entry size set, sz=%zu", entry.ptr.size); test_assert(!memcmp(nettree->tree + nettree->namesz, mtree.tree, HASHSIZE * mtree.nodes), "mtree matches sz=%zu", entry.ptr.size); /* test hash of filename returns root hash via alias */ memset(&entry, 0, sizeof entry); rc = mdex_getalias(mdex, src, &entry); test_assert(rc == 0, "mdex_getalias() returned %i", rc); min = mtree_subtree_data_min(mtree.base, 0); max = min + mtree.chunks; for (size_t z = min; z < max; z++) { hash = mtree_nnode(&mtree, z); hash_hex_debug(stderr, hash, HASHSIZE); assert(hash); rc = mdex_get(mdex, hash, HASHSIZE, &entry); test_assert(rc == 0, "hash found"); test_assert((entry.type & MDEX_FILE), "entry type set"); size_t expected = MIN(MTREE_CHUNKSIZE, len); test_assert(entry.file.size == expected, "%03zu: size %zu == %zu matches", z, entry.file.size, expected); test_assert(entry.file.off == off, "offset matches"); test_assert(entry.file.file.ref == 1, "file refcount set"); test_assert(!strcmp(entry.file.file.name, src), "filename set"); off += MTREE_CHUNKSIZE; len -= MTREE_CHUNKSIZE; } mtree_free(&mtree); mdex_free(mdex); close(fds); unlink(src); exit_0: return test_status; } librecast/test/0000-0055.c000066400000000000000000000076121502456746400151420ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2023-2024 Brett Sheffield */ #include "testnet.h" #include "testdata.h" #include #include #include #include #include #include #include #define TIMEOUT_SECONDS 300 #ifdef HAVE_RQ_OTI static sem_t sem_recv; struct pkg_s { void *data; size_t len; uint8_t *hash; }; void *thread_recv(void *arg) { struct pkg_s *pkg = (struct pkg_s *)arg; lc_ctx_t *lctx = lc_ctx_new(); pthread_cleanup_push((void (*)(void *))lc_ctx_free, lctx); hash_hex_debug(stderr, pkg->hash, HASHSIZE); lc_sync(lctx, pkg->hash, pkg->data, pkg->len, NULL, NULL, NULL, 0); pthread_cleanup_pop(1); /* lc_ctx_free */ sem_post(&sem_recv); return NULL; } void hash_testdata(unsigned char *hash, void *data, size_t sz) { mtree_t tree = {0}; mtree_init(&tree, sz); mtree_build(&tree, data, NULL); memcpy(hash, mtree_nnode(&tree, 0), HASHSIZE); mtree_free(&tree); } int runtest_size(size_t TEST_SIZE) { unsigned char *src, *dst; unsigned char hash[HASHSIZE]; unsigned char root[HASHSIZE]; mdex_t *mdex; lc_ctx_t *lctx; lc_share_t *share; pthread_t tid_recv; struct pkg_s pkg_recv = {0}; struct timespec timeout = {0}; int rc; /* create random test data */ src = malloc(TEST_SIZE); test_assert(src != NULL, "malloc(src) = %p, TEST_SIZE = %zu", (void *)src, TEST_SIZE); if (!src) return test_status; test_random_bytes(src, TEST_SIZE); hash_testdata(hash, src, TEST_SIZE); /* add test data to index */ mdex = mdex_init(0); if (test_assert(mdex != NULL, "mdex_init(0) = %p", (void *)mdex)) goto free_src; rc = mdex_add(mdex, src, TEST_SIZE, NULL, 0); if (test_assert(rc == 0, "mdex_add() returned %i", rc)) goto err_mdex_free; size_t z = 0; hash_generic_key(root, HASHSIZE, hash, HASHSIZE, (unsigned char *)&z, sizeof(z)); rc = mdex_get(mdex, root, sizeof root, NULL); if (test_assert(rc == 0, "root hash in mdex")) goto err_mdex_free; /* share the mdex */ lctx = lc_ctx_new(); if (test_assert(lctx != NULL, "lc_ctx_new() = %p", (void *)lctx)) goto err_mdex_free; share = lc_share(lctx, mdex, 0, NULL, NULL, LC_SHARE_LOOPBACK); if (test_assert(share != NULL, "lc_share()")) goto err_ctx_free; /* allocate dst */ dst = malloc(TEST_SIZE); test_assert(dst != NULL, "malloc(dst) = %p, TEST_SIZE = %zu", (void *)dst, TEST_SIZE); if (!dst) goto err_unshare; memset(dst, 0, TEST_SIZE); rc = sem_init(&sem_recv, 0, 0); if (test_assert(rc == 0, "sem_init(sem_recv) returned %i", rc)) goto err_free_dst; pkg_recv.data = dst; pkg_recv.len = TEST_SIZE; pkg_recv.hash = root; rc = pthread_create(&tid_recv, NULL, thread_recv, &pkg_recv); if (test_assert(rc == 0, "pthread_create returned %i", rc)) goto err_sem_destroy; rc = clock_gettime(CLOCK_REALTIME, &timeout); if (test_assert(rc == 0, "clock_gettime returned %i", rc)) goto err_sem_destroy; timeout.tv_sec += TIMEOUT_SECONDS; if ((rc = sem_timedwait(&sem_recv, &timeout)) == -1 && errno == ETIMEDOUT) { pthread_cancel(tid_recv); } test_assert(rc == 0, "timeout waiting for recv thread"); pthread_join(tid_recv, NULL); if (rc == 0) { test_assert(!memcmp(dst, src, TEST_SIZE), "src matches dst"); } /* clean up */ err_sem_destroy: sem_destroy(&sem_recv); err_free_dst: free(dst); err_unshare: lc_unshare(share); err_ctx_free: lc_ctx_free(lctx); err_mdex_free: mdex_free(mdex); free_src: free(src); return test_status; } #endif /* HAVE_RQ_OTI */ int main(void) { #if defined HAVE_MLD && defined HAVE_RQ_OTI test_cap_require(CAP_NET_ADMIN); test_name("lc_sync()"); test_require_net(TEST_NET_BASIC); runtest_size(1024 * 31 + 5); /* single node */ runtest_size(1024 * 100 + 5); runtest_size(1024 * 1024 + 5); /* larger tree with padding chunks */ runtest_size(1024 * 1024 * 32 + 5); /* multi-part tree */ return test_status; #else return test_skip("lc_sync()"); #endif } librecast/test/0000-0056.c000066400000000000000000000070041502456746400151360ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2023-2024 Brett Sheffield */ #include "testnet.h" #include "testdata.h" #include #include #include #include #include #include #include #ifdef HAVE_RQ_OTI #define TIMEOUT_SECONDS 100 #define TEST_SIZE 1024 * 100 + 5 /* nice powers of two hide bugs - ensure test size is odd */ static_assert(TEST_SIZE % 2, "TEST_SIZE must be an odd number"); static sem_t sem_recv; struct pkg_s { char *dst; uint8_t *hash; }; void *thread_recv(void *arg) { struct pkg_s *pkg = (struct pkg_s *)arg; lc_ctx_t *lctx = lc_ctx_new(); pthread_cleanup_push((void (*)(void *))lc_ctx_free, lctx); hash_hex_debug(stderr, pkg->hash, HASHSIZE); lc_syncfile(lctx, pkg->hash, pkg->dst, NULL, NULL, NULL, 0); pthread_cleanup_pop(1); /* lc_ctx_free */ sem_post(&sem_recv); return NULL; } #endif /* HAVE_RQ_OTI */ int main(void) { #if HAVE_MLD && HAVE_RQ_OTI struct stat sb; char src[] = "0000-0056.src.tmp.XXXXXX"; char dst[] = "0000-0056.dst.tmp.XXXXXX"; unsigned char *testdata; unsigned char root[HASHSIZE]; mdex_t *mdex; mtree_t mtree = {0}; lc_ctx_t *lctx; lc_share_t *share; pthread_t tid_recv; struct pkg_s pkg_recv = {0}; struct timespec timeout = {0}; size_t off; int fds, rc; test_cap_require(CAP_NET_ADMIN); test_name("lc_syncfile()"); test_require_net(TEST_NET_BASIC); /* create test file */ fds = test_data_file(src, TEST_SIZE, TEST_TMP | TEST_RND); test_assert(fds != -1, "test_data_file()"); if (fds == -1) goto exit_0; test_assert(test_data_size(src, TEST_SIZE) == 0, "source exists and is correct size"); test_assert(stat(src, &sb) != -1, "stat source file"); /* set destination filename */ off = strlen(src) - 6; memcpy(dst + off, src + off, 6); /* add test data to index */ mdex = mdex_init(0); rc = mdex_addfile(mdex, src, NULL, 0); test_assert(rc == 0, "mdex_addfile() returned %i", rc); /* map file, build tree */ size_t sz = 0; testdata = lc_mmapfile(src, &sz, PROT_READ, MAP_PRIVATE, 0, &sb); rc = mtree_init(&mtree, TEST_SIZE); test_assert(rc == 0, "mtree_init() returned %i", rc); rc = mtree_build(&mtree, testdata, NULL); test_assert(rc == 0, "mtree_build() returned %i", rc); /* ensure root hash is in mdex */ mdex_tree_hash_sb(root, sizeof root, &mtree, 0, &sb, src); rc = mdex_get(mdex, root, sizeof root, NULL); test_assert(rc == 0, "root hash in mdex"); /* share the mdex */ lctx = lc_ctx_new(); share = lc_share(lctx, mdex, 0, NULL, NULL, LC_SHARE_LOOPBACK); test_assert(share != NULL, "lc_share()"); /* sync files */ sem_init(&sem_recv, 0, 0); pkg_recv.dst = dst; pkg_recv.hash = root; pthread_create(&tid_recv, NULL, thread_recv, &pkg_recv); clock_gettime(CLOCK_REALTIME, &timeout); timeout.tv_sec += TIMEOUT_SECONDS; if ((rc = sem_timedwait(&sem_recv, &timeout)) == -1 && errno == ETIMEDOUT) { pthread_cancel(tid_recv); } test_assert(rc == 0, "timeout waiting for recv thread"); pthread_join(tid_recv, NULL); if (rc == 0) { /* verify data matches */ test_assert(test_data_size(dst, sz) == 0, "destination exists and is correct size"); test_assert(test_file_match(dst, src) == 0, "source and destination data matches"); } /* clean up */ sem_destroy(&sem_recv); lc_unshare(share); lc_ctx_free(lctx); munmap(testdata, sz); mtree_free(&mtree); mdex_free(mdex); close(fds); unlink(dst); unlink(src); exit_0: return test_status; #else return test_skip("lc_syncfile()"); #endif } librecast/test/0000-0057.c000066400000000000000000000075241502456746400151460ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2017-2022 Brett Sheffield */ /* symmetric encryption test - key set on context */ #include "testnet.h" #include #include #include #include #include #include #include #include #define WAITS 1 #ifdef HAVE_LIBSODIUM static sem_t sem; static ssize_t byt_recv, byt_sent, ohead; static char channame[] = "0000-0057"; static unsigned char key[crypto_secretbox_KEYBYTES]; static int encryption_on; void *testthread(void *arg) { lc_ctx_t *lctx; lc_socket_t *sock; lc_channel_t *chan; lctx = lc_ctx_new(); test_assert(lctx != NULL, "lc_ctx_new()"); if (encryption_on) { lc_ctx_set_sym_key(lctx, key, crypto_secretbox_KEYBYTES); lc_ctx_coding_set(lctx, LC_CODE_SYMM); ohead = crypto_secretbox_MACBYTES + crypto_secretbox_NONCEBYTES; } sock = lc_socket_new(lctx); test_assert(sock != NULL, "lc_socket_new()"); chan = lc_channel_new(lctx, channame); test_assert(chan != NULL, "lc_channel_new()"); test_assert(lc_channel_bind(sock, chan) == 0, "lc_channel_bind()"); test_assert(lc_channel_join(chan) == 0, "lc_channel_join()"); sem_post(&sem); /* tell send thread we're ready */ byt_recv = lc_socket_recv(sock, (char *)arg, BUFSIZ, 0); if (byt_recv == -1) perror("lc_socket_recv"); lc_ctx_free(lctx); sem_post(&sem); /* tell send thread we're done */ return arg; } #endif int main(void) { #ifndef HAVE_LIBSODIUM return test_skip("lc_channel_send() / lc_socket_recv() - symmetric encryption"); #else lc_ctx_t *lctx; lc_socket_t *sock; lc_channel_t *chan; pthread_t thread; struct timespec ts; char buf[] = "liberté"; char recvbuf[BUFSIZ] = ""; test_name("lc_channel_send() / lc_socket_recv() - symmetric encryption (ctx key)"); test_require_net(TEST_NET_BASIC); /* fire up test thread */ sem_init(&sem, 0, 0); pthread_create(&thread, NULL, &testthread, &recvbuf); sem_wait(&sem); /* recv thread is ready */ /* Librecast Context, Socket + Channel */ lctx = lc_ctx_new(); test_assert(lctx != NULL, "lc_ctx_new()"); /* generate and set symmetric key on sender */ crypto_secretbox_keygen(key); lc_ctx_set_sym_key(lctx, key, crypto_secretbox_KEYBYTES); lc_ctx_coding_set(lctx, LC_CODE_SYMM); /* create socket and channel (channel will inherit encoding from ctx) */ sock = lc_socket_new(lctx); test_assert(sock != NULL, "lc_socket_new()"); chan = lc_channel_new(lctx, channame); test_assert(chan != NULL, "lc_channel_new()"); lc_socket_loop(sock, 1); /* talking to ourselves, set loopback */ lc_channel_bind(sock, chan); /* send msg with PING opcode */ byt_sent = lc_channel_send(chan, buf, sizeof buf, 0); /* wait for recv thread */ test_assert(!clock_gettime(CLOCK_REALTIME, &ts), "clock_gettime()"); ts.tv_sec += WAITS; test_assert(!sem_timedwait(&sem, &ts), "timeout"); pthread_cancel(thread); pthread_join(thread, NULL); test_assert(memcmp(buf, recvbuf, sizeof buf) != 0, "data doesn't match with encryption"); /* run testthread again with encryption key set */ encryption_on = 1; pthread_create(&thread, NULL, &testthread, &recvbuf); sem_wait(&sem); /* recv thread is ready */ byt_sent = lc_channel_send(chan, buf, sizeof buf, 0); /* wait for recv thread */ test_assert(!clock_gettime(CLOCK_REALTIME, &ts), "clock_gettime()"); ts.tv_sec += WAITS; test_assert(!sem_timedwait(&sem, &ts), "timeout"); sem_destroy(&sem); /* test we can decrypt message */ if (byt_recv > 0) { test_assert(byt_recv == sizeof buf, "received %zi bytes, expected %zu", byt_recv, sizeof buf); test_expect(buf, recvbuf); } test_assert(byt_sent - ohead == byt_recv, "bytes sent (%zi) == bytes received (%zi)", byt_sent, byt_recv); /* clean up */ pthread_cancel(thread); pthread_join(thread, NULL); lc_ctx_free(lctx); return test_status; #endif } librecast/test/0000-0058.c000066400000000000000000000105741502456746400151460ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2017-2022 Brett Sheffield */ /* symmetric encryption test using key on context (msg functions) */ #include "testnet.h" #include #include #include #include #include #include #include #include #define WAITS 1 #ifdef HAVE_LIBSODIUM static sem_t sem; static ssize_t byt_recv, byt_sent, ohead; static char channame[] = "0000-0058"; static char data[] = "black lives matter"; static unsigned char key[crypto_secretbox_KEYBYTES]; static int encryption_on; void *testthread(void *arg) { lc_ctx_t *lctx; lc_socket_t *sock; lc_channel_t *chan; lc_message_t *msg = (lc_message_t *)arg; char buf[BUFSIZ]; lc_msg_init(msg); msg->data = buf; msg->len = BUFSIZ; lctx = lc_ctx_new(); test_assert(lctx != NULL, "lc_ctx_new()"); if (encryption_on) { lc_ctx_set_sym_key(lctx, key, crypto_secretbox_KEYBYTES); lc_ctx_coding_set(lctx, LC_CODE_SYMM); ohead = crypto_secretbox_MACBYTES + crypto_secretbox_NONCEBYTES; } sock = lc_socket_new(lctx); test_assert(sock != NULL, "lc_socket_new()"); chan = lc_channel_new(lctx, channame); test_assert(chan != NULL, "lc_channel_new()"); test_assert(lc_channel_bind(sock, chan) == 0, "lc_channel_bind()"); test_assert(lc_channel_join(chan) == 0, "lc_channel_join()"); sem_post(&sem); /* tell send thread we're ready */ byt_recv = lc_msg_recv(sock, msg); lc_ctx_free(lctx); sem_post(&sem); /* tell send thread we're done */ return arg; } #endif int main(void) { #ifndef HAVE_LIBSODIUM return test_skip("lc_msg_send() / lc_msg_recv() - symmetric encryption"); #else lc_ctx_t *lctx; lc_socket_t *sock; lc_channel_t *chan; lc_message_t msg_out, msg_in; pthread_t thread; struct timespec ts; unsigned op; test_name("lc_msg_send() / lc_msg_recv() - symmetric encryption (ctx key)"); test_require_net(TEST_NET_BASIC); /* fire up test thread */ sem_init(&sem, 0, 0); pthread_create(&thread, NULL, &testthread, &msg_in); sem_wait(&sem); /* recv thread is ready */ /* Librecast Context, Socket + Channel */ lctx = lc_ctx_new(); test_assert(lctx != NULL, "lc_ctx_new()"); /* generate and set symmetric key on sender */ crypto_secretbox_keygen(key); lc_ctx_set_sym_key(lctx, key, crypto_secretbox_KEYBYTES); lc_ctx_coding_set(lctx, LC_CODE_SYMM); /* create socket and channel with key from ctx */ sock = lc_socket_new(lctx); test_assert(sock != NULL, "lc_socket_new()"); chan = lc_channel_new(lctx, channame); test_assert(chan != NULL, "lc_channel_new()"); lc_socket_loop(sock, 1); /* talking to ourselves, set loopback */ lc_channel_bind(sock, chan); /* send msg with PING opcode */ op = LC_OP_PING; lc_msg_init_data(&msg_out, data, strlen(data), NULL, NULL); test_log("msg (out): '%.*s'\n", (int)msg_out.len, msg_out.data); lc_msg_set(&msg_out, LC_ATTR_OPCODE, &op); byt_sent = lc_msg_send(chan, &msg_out); lc_msg_free(&msg_out); /* clear struct before recv */ /* wait for recv thread */ test_assert(!clock_gettime(CLOCK_REALTIME, &ts), "clock_gettime()"); ts.tv_sec += WAITS; test_assert(!sem_timedwait(&sem, &ts), "timeout"); pthread_cancel(thread); pthread_join(thread, NULL); test_assert(memcmp(data, msg_in.data, strlen(data)) != 0, "encrypted data doesn't match"); lc_msg_free(&msg_in); /* run testthread again with encryption key set */ encryption_on = 1; pthread_create(&thread, NULL, &testthread, &msg_in); sem_wait(&sem); /* recv thread is ready */ op = LC_OP_PING; lc_msg_init_data(&msg_out, data, strlen(data), NULL, NULL); test_log("msg (out): '%.*s'\n", (int)msg_out.len, msg_out.data); lc_msg_set(&msg_out, LC_ATTR_OPCODE, &op); byt_sent = lc_msg_send(chan, &msg_out); lc_msg_free(&msg_out); /* clear struct before recv */ /* wait for recv thread */ test_assert(!clock_gettime(CLOCK_REALTIME, &ts), "clock_gettime()"); ts.tv_sec += WAITS; test_assert(!sem_timedwait(&sem, &ts), "timeout"); sem_destroy(&sem); test_assert(memcmp(data, msg_in.data, strlen(data)) == 0, "decrypted data matches"); test_assert(msg_in.op == LC_OP_PING, "opcode matches"); test_assert(byt_sent - ohead == byt_recv, "bytes sent (%zi) == bytes received (%zi)", byt_sent, byt_recv); /* clean up */ pthread_cancel(thread); pthread_join(thread, NULL); lc_msg_free(&msg_out); lc_msg_free(&msg_in); lc_ctx_free(lctx); return test_status; #endif } librecast/test/0000-0059.c000066400000000000000000000077071502456746400151530ustar00rootroot00000000000000#include "testnet.h" #include #include #include #include #define WAITS 1 #ifdef HAVE_LIBSODIUM static char channel_name[] = "0000-0060"; static sem_t sem; static ssize_t bytes = -1; static unsigned char key[crypto_secretbox_KEYBYTES]; static int encryption_on = 0; static char recvbuf[8]; static char recvbuf2[8]; static void *listen_thread(void *arg) { lc_ctx_t * lctx; lc_socket_t * sock; lc_channel_t * chan; struct iovec iov[2]; struct msghdr msg = {0}; lctx = lc_ctx_new(); if (encryption_on) { lc_ctx_set_sym_key(lctx, key, crypto_secretbox_KEYBYTES); lc_ctx_coding_set(lctx, LC_CODE_SYMM); } sock = lc_socket_new(lctx); chan = lc_channel_new(lctx, channel_name); iov[0].iov_base = recvbuf; iov[0].iov_len = sizeof recvbuf; iov[1].iov_base = recvbuf2; iov[1].iov_len = sizeof recvbuf2; msg.msg_iov = iov; msg.msg_iovlen = 2; lc_channel_bind(sock, chan); lc_channel_join(chan); sem_post(&sem); /* tell send thread we're ready */ bytes = lc_socket_recvmsg(sock, &msg, 0); sem_post(&sem); /* tell send thread we're done */ lc_ctx_free(lctx); return arg; } #endif int main(void) { #ifndef HAVE_LIBSODIUM return test_skip("lc_channel_sendmsg() / lc_socket_recvmsg() - symmetric encryption"); #else lc_ctx_t * lctx; lc_socket_t * sock; lc_channel_t * chan; pthread_t thread; struct timespec ts; char buf[8] = "liberte"; char buf2[8] = "egalite"; struct iovec iov[2]; struct msghdr msg = {0}; ssize_t sentbyt; test_name("lc_channel_sendmsg() / lc_socket_recvmsg() - symmetric encryption (enc)"); test_require_net(TEST_NET_BASIC); sem_init(&sem, 0, 0); pthread_create(&thread, NULL, &listen_thread, &recvbuf); sem_wait(&sem); /* recv thread is ready */ lctx = lc_ctx_new(); /* generate and set symmetric key on sender */ crypto_secretbox_keygen(key); lc_ctx_set_sym_key(lctx, key, crypto_secretbox_KEYBYTES); lc_ctx_coding_set(lctx, LC_CODE_SYMM); sock = lc_socket_new(lctx); chan = lc_channel_new(lctx, channel_name); iov[0].iov_base = buf; iov[0].iov_len = strlen(buf) + 1; iov[1].iov_base = buf2; iov[1].iov_len = strlen(buf2) + 1; msg.msg_iov = iov; msg.msg_iovlen = 2; sentbyt = 0; for (size_t z = 0; z < (size_t)msg.msg_iovlen; z++) sentbyt += iov[z].iov_len; lc_socket_loop(sock, 1); lc_channel_bind(sock, chan); lc_channel_sendmsg(chan, &msg, 0); test_assert(!clock_gettime(CLOCK_REALTIME, &ts), "clock_gettime()"); ts.tv_sec += WAITS; test_assert(!sem_timedwait(&sem, &ts), "timeout"); sem_timedwait(&sem, &ts); pthread_cancel(thread); pthread_join(thread, NULL); test_assert(bytes == sentbyt, "0: received %zi bytes, expected %zu", bytes, sentbyt); /* we can't really prove the data is encrypted, but we can at least * check it isn't the same as what we sent */ test_assert(memcmp(buf, recvbuf, sizeof buf - 1) != 0, "data doesn't match with encryption"); /* now receive again with key */ encryption_on = 1; pthread_create(&thread, NULL, &listen_thread, &recvbuf); sem_wait(&sem); /* recv thread is ready */ iov[0].iov_base = buf; iov[0].iov_len = strlen(buf) + 1; test_log("iov[0].iov_len = %zu\n", iov[0].iov_len); iov[1].iov_base = buf2; iov[1].iov_len = strlen(buf2) + 1; test_log("iov[1].iov_len = %zu\n", iov[1].iov_len); msg.msg_iov = iov; msg.msg_iovlen = 2; sentbyt = 0; for (size_t z = 0; z < (size_t)msg.msg_iovlen; z++) sentbyt += iov[z].iov_len; lc_channel_sendmsg(chan, &msg, 0); test_assert(!clock_gettime(CLOCK_REALTIME, &ts), "clock_gettime()"); ts.tv_sec += WAITS; test_assert(!sem_timedwait(&sem, &ts), "timeout"); sem_timedwait(&sem, &ts); sem_destroy(&sem); pthread_cancel(thread); pthread_join(thread, NULL); test_assert(bytes == sentbyt, "1: received %zi bytes, expected %zu", bytes, sentbyt); test_assert(memcmp(buf, recvbuf, sizeof buf - 1) == 0, "data decrypts [0]"); test_assert(memcmp(buf2, recvbuf2, sizeof buf2 - 1) == 0, "data decrypts [1]"); lc_ctx_free(lctx); return test_status; #endif } librecast/test/0000-0060.c000066400000000000000000000122761502456746400151400ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2017-2025 Brett Sheffield */ #include "testnet.h" #include #include #include #include #include #include #include #include #include #undef TESTDEBUG #ifdef TESTDEBUG # define PKTS 10 # define PKTSZ 4 #else # define PKTS 20 # define PKTSZ 1024 #endif #define WAITS 20 #ifdef HAVE_LIBSODIUM #ifdef HAVE_LIBLCRQ enum { TID_SEND, TID_RECV }; static const size_t SZ = PKTS * PKTSZ + 5; static char channel_name[] = "0000-0060"; static sem_t receiver_ready, timeout; static int fec; static unsigned char key[crypto_secretbox_KEYBYTES]; #ifdef TESTDEBUG #if 0 static void dumppkt(uint8_t *pkt, int haseq) { uint16_t seq; uint8_t *dat = pkt; if (haseq) { dat += sizeof seq; seq = ntohs(*(uint16_t *)pkt); fprintf(stderr, "%u: ", seq); } else fprintf(stderr, " "); for (size_t z = 0; z < PKTSZ * 8; z++) { if (isset(dat, z)) putc('1', stderr); else putc('0', stderr); } putc('\n', stderr); } #endif static void dump_bufs(uint8_t buf[2][SZ]) { for (size_t p = 0; p < PKTS; p++) { fprintf(stderr, "%zu: ", p); for (int i = 0; i < 2; i++) { for (size_t z = 0; z < PKTSZ * 8; z++) { uint8_t *b = buf[i]; if (isset(b, p * PKTSZ * 8 + z)) putc('1', stderr); else putc('0', stderr); } putc(' ', stderr); } putc('\n', stderr); } putc('\n', stderr); } #endif static void generate_source_data(uint8_t *buf, size_t sz) { ssize_t rc; int f; f = open("/dev/urandom", O_RDONLY); if (f == -1) return; rc = read(f, buf, sz); test_assert(rc == (ssize_t)sz, "%zi random bytes read", rc); close(f); } static void *recv_data_fec(void *arg) { uint8_t *buf = (uint8_t *)arg; ssize_t rc; lc_ctx_t *lctx; lc_socket_t *sock; lc_channel_t *chan; memset(buf, 0, SZ); /* clear receive buffer */ lctx = lc_ctx_new(); pthread_cleanup_push((void (*)(void *))lc_ctx_free, lctx); lc_ctx_set_sym_key(lctx, key, crypto_secretbox_KEYBYTES); lc_ctx_coding_set(lctx, LC_CODE_SYMM | LC_CODE_FEC_RQ); sock = lc_socket_new(lctx); chan = lc_channel_new(lctx, channel_name); lc_channel_bind(sock, chan); lc_channel_join(chan); sem_post(&receiver_ready); rc = lc_channel_recv(chan, buf, SZ, 0); test_assert(rc != -1, "lc_channel_recv returned %zi\n", rc); test_assert(rc >= (ssize_t)SZ, "data received %zi/%zu bytes", rc, SZ); lc_channel_part(chan); pthread_cleanup_pop(1); /* lc_ctx_free(lctx); */ sem_post(&timeout); return arg; } static void *send_data_fec(void *arg) { uint8_t *buf = (uint8_t *)arg; lc_ctx_t *lctx; lc_socket_t *sock; lc_channel_t *chan; rq_t *rq; ssize_t rc; size_t byt = 0; lctx = lc_ctx_new(); pthread_cleanup_push((void (*)(void *))lc_ctx_free, lctx); lc_ctx_set_sym_key(lctx, key, crypto_secretbox_KEYBYTES); lc_ctx_coding_set(lctx, LC_CODE_SYMM | LC_CODE_FEC_RQ); sock = lc_socket_new(lctx); chan = lc_channel_new(lctx, channel_name); lc_socket_loop(sock, 1); lc_channel_bind(sock, chan); test_log("sending data with FEC + symmetric encryption\n"); sem_wait(&receiver_ready); rc = lc_channel_send(chan, buf, SZ, 0); test_assert(rc > 0, "lc_channel_send encoded data, returned %zi", rc); if (rc == -1) goto err_ctx_free; byt = rc; rq = lc_channel_rq(chan); test_assert(rq != NULL, "lcrq context = %p", (void *)rq); if (!rq) goto err_ctx_free; /* Send packets. Drop packet 3 */ int pkts = rq_KP(rq) + RQ_OVERHEAD * 2; test_log("sending %u packets\n", pkts); for (int i = 1; i < pkts; i++) { int flags = (i == 3) ? MSG_DROP : 0; rc = lc_channel_send(chan, NULL, 0, flags); test_assert(rc > 0, "lc_channel_send encoded data, returned %zi", rc); if (rc > 0) byt += rc; } test_assert(byt >= SZ, "data sent %zi bytes (buffer = %zu)", byt, SZ); err_ctx_free: pthread_cleanup_pop(1); /* lc_ctx_free(lctx); */ return arg; } #endif #endif int main(void) { #if !defined(HAVE_LIBLCRQ) || !(HAVE_LIBSODIUM) return test_skip("lc_channel_send() / lc_socket_recv() - FEC + encrypt (ctx)"); #else pthread_t tid[2]; uint8_t buf[2][SZ]; struct timespec ts; test_name("lc_channel_send() / lc_socket_recv() - FEC + encrypt (ctx)"); test_require_net(TEST_NET_BASIC); /* run test twice */ for (fec = 0; fec < 2; fec++) { /* generate symmetric encryption key */ crypto_secretbox_keygen(key); /* clear buffers */ memset(buf[0], 0, SZ); memset(buf[1], 0, SZ); sem_init(&timeout, 0, 0); sem_init(&receiver_ready, 0, 0); generate_source_data(buf[TID_SEND], SZ); test_assert(memcmp(buf[TID_RECV], buf[TID_SEND], SZ), "buffer differ before sync"); pthread_create(&tid[TID_SEND], NULL, &send_data_fec, buf[TID_SEND]); pthread_create(&tid[TID_RECV], NULL, &recv_data_fec, buf[TID_RECV]); clock_gettime(CLOCK_REALTIME, &ts); ts.tv_sec += WAITS; test_assert(!sem_timedwait(&timeout, &ts), "timeout"); pthread_cancel(tid[TID_RECV]); pthread_join(tid[TID_RECV], NULL); pthread_cancel(tid[TID_SEND]); pthread_join(tid[TID_SEND], NULL); sem_destroy(&receiver_ready); sem_destroy(&timeout); test_assert(!memcmp(buf[TID_RECV], buf[TID_SEND], SZ), "send buffer matches received"); #ifdef TESTDEBUG dump_bufs(buf); #endif } return test_status; #endif } librecast/test/0000-0061.c000066400000000000000000000014411502456746400151310ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2023 Brett Sheffield */ /* test canonpath() * * canonpath() is the same as glibc's realpath(3), except it does not resolve * symlinks */ #include "test.h" #include "testdata.h" #include int main(int argc, char *argv[]) { (void)argc; char *src, *csrc, *rsrc; test_name("canonpath()"); test_createtestdir(basename(argv[0]), &src, "src"); csrc = canonpath(src); rsrc = realpath(src, NULL); test_log("src: '%s'\n", src); test_log("csrc: '%s'\n", csrc); test_log("rsrc: '%s'\n", rsrc); test_assert(csrc != NULL, "canonpath() did not return NULL"); test_assert(!strcmp(csrc, rsrc), "canonpath() == realpath()"); free(rsrc); free(csrc); free(src); return test_status; } librecast/test/0000-0062.c000066400000000000000000000067621502456746400151450ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2023 Brett Sheffield */ #include "testnet.h" #include "testdata.h" #include #include #include #include #include #include #include #define TIMEOUT_SECONDS 100 #define TEST_SIZE 1024 * 1024 * 1024 + 5 /* nice powers of two hide bugs - ensure test size is odd */ static_assert(TEST_SIZE % 2, "TEST_SIZE must be an odd number"); static sem_t sem_recv; struct pkg_s { char *dst; uint8_t *hash; }; void *thread_recv(void *arg) { struct pkg_s *pkg = (struct pkg_s *)arg; lc_ctx_t *lctx = lc_ctx_new(); pthread_cleanup_push((void (*)(void *))lc_ctx_free, lctx); hash_hex_debug(stderr, pkg->hash, HASHSIZE); lc_syncfile(lctx, pkg->hash, pkg->dst, NULL, NULL, NULL, 0); pthread_cleanup_pop(1); /* lc_ctx_free */ sem_post(&sem_recv); return NULL; } int main(void) { #if HAVE_MLD struct stat sb; char src[] = "0000-0062.src.tmp.XXXXXX"; char dst[] = "0000-0062.dst.tmp.XXXXXX"; unsigned char *testdata; unsigned char root[HASHSIZE]; mdex_t *mdex; mtree_t mtree = {0}; lc_ctx_t *lctx; lc_share_t *share; pthread_t tid_recv; struct pkg_s pkg_recv = {0}; struct timespec timeout = {0}; size_t off; int fds, rc; test_cap_require(CAP_NET_ADMIN); test_name("lc_syncfile() - large file (1GiB)"); test_require_net(TEST_NET_BASIC); /* create test file */ fds = test_data_file(src, TEST_SIZE, TEST_TMP | TEST_RND); test_assert(fds != -1, "test_data_file()"); if (fds == -1) goto exit_0; test_assert(test_data_size(src, TEST_SIZE) == 0, "source exists and is correct size"); test_assert(stat(src, &sb) != -1, "stat source file"); /* set destination filename */ off = strlen(src) - 6; memcpy(dst + off, src + off, 6); /* add test data to index */ mdex = mdex_init(0); rc = mdex_addfile(mdex, src, NULL, 0); test_assert(rc == 0, "mdex_addfile() returned %i", rc); /* map file, build tree */ size_t sz = 0; testdata = lc_mmapfile(src, &sz, PROT_READ, MAP_PRIVATE, 0, &sb); rc = mtree_init(&mtree, TEST_SIZE); test_assert(rc == 0, "mtree_init() returned %i", rc); rc = mtree_build(&mtree, testdata, NULL); test_assert(rc == 0, "mtree_build() returned %i", rc); /* ensure root hash is in mdex */ mdex_tree_hash_sb(root, sizeof root, &mtree, 0, &sb, src); rc = mdex_get(mdex, root, sizeof root, NULL); if (!test_assert(rc == 0, "root hash in mdex")) goto exit_0; /* share the mdex */ lctx = lc_ctx_new(); share = lc_share(lctx, mdex, 0, NULL, NULL, LC_SHARE_LOOPBACK); test_assert(share != NULL, "lc_share()"); /* sync files */ sem_init(&sem_recv, 0, 0); pkg_recv.dst = dst; pkg_recv.hash = root; pthread_create(&tid_recv, NULL, thread_recv, &pkg_recv); clock_gettime(CLOCK_REALTIME, &timeout); timeout.tv_sec += TIMEOUT_SECONDS; if ((rc = sem_timedwait(&sem_recv, &timeout)) == -1 && errno == ETIMEDOUT) { pthread_cancel(tid_recv); } test_assert(rc == 0, "timeout waiting for recv thread"); pthread_join(tid_recv, NULL); if (rc == 0) { /* verify data matches */ test_assert(test_data_size(dst, sz) == 0, "destination exists and is correct size"); test_assert(test_file_match(dst, src) == 0, "source and destination data matches"); } /* clean up */ sem_destroy(&sem_recv); lc_unshare(share); lc_ctx_free(lctx); munmap(testdata, sz); mtree_free(&mtree); mdex_free(mdex); close(fds); unlink(dst); unlink(src); exit_0: return test_status; #else return test_skip("lc_syncfile()"); #endif } librecast/test/0000-0063.c000066400000000000000000000076301502456746400151410ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2024 Brett A C Sheffield */ /* Ensure multicast packets are sent by default on ALL capable interfaces */ #include "test.h" #include "testnet.h" #include #include #include #include #include #include #define TIMEOUT_SECONDS 2 static sem_t sem; static lc_ctx_t *lctx; static char channel_name[] = "0000-0063"; void *thread_listen(void *arg) { unsigned int ifx = *(unsigned int *)arg; char buf[1024]; lc_socket_t *sock; lc_channel_t *chan; ssize_t byt; int rc; sock = lc_socket_new(lctx); if (!test_assert(sock != NULL, "lc_socket_new")) return NULL; chan = lc_channel_new(lctx, channel_name); if (!test_assert(chan != NULL, "lc_channel_new")) return NULL; rc = lc_socket_bind(sock, ifx); if (!test_assert(rc == 0, "lc_socket_bind")) return NULL; /* bind socket to ifx so we only get packets on that interface */ rc = lc_channel_bind(sock, chan); if (!test_assert(rc == 0, "lc_channel_bind")) return NULL; rc = lc_channel_join(chan); if (!test_assert(rc == 0, "lc_channel_join")) return NULL; test_log("listening on ifx = %u\n", ifx); sem_post(&sem); /* tell sender we're ready */ byt = lc_socket_recv(sock, buf, sizeof buf, 0); test_assert(byt > 0, "%zi bytes received on ifx %u", byt, ifx); sem_post(&sem); return NULL; } int push_ifx(unsigned int ifxa[], int ifcount, char *ifname) { unsigned int ifx = if_nametoindex(ifname); if (ifx) for (int i = 0; i < ifcount; i++) { if (ifxa[i] == ifx) return 0; } ifxa[ifcount] = ifx; return 1; } int main(void) { char name[] = "lc_channel_send - send on ALL interfaces by default"; lc_socket_t *sock; lc_channel_t *chan; unsigned int ifxa[16]; struct ifaddrs *ifap; pthread_t tid[16]; ssize_t byt; int ifcount = 0; int rc; test_name(name); test_require_net(TEST_NET_BASIC); /* Set up listeners on all multicast capable interfaces */ rc = getifaddrs(&ifap); test_assert(rc == 0, "getifaddrs(3)"); /* find interfaces with multicast enabled */ for (struct ifaddrs *ifa = ifap; ifa; ifa = ifa->ifa_next) { if (ifa->ifa_addr->sa_family != AF_INET6) continue; /* IPv6 */ if (!(ifa->ifa_flags & IFF_MULTICAST)) continue; /* multicast */ if (ifa->ifa_addr == NULL) continue; ifcount += push_ifx(ifxa, ifcount, ifa->ifa_name); if (ifcount == sizeof ifxa / sizeof ifxa[0]) break; } freeifaddrs(ifap); test_log("%i interfaces\n", ifcount); /* create socket and channel for sending */ lctx = lc_ctx_new(); if (!test_assert(lctx != NULL, "lc_ctx_new()")) return test_status; sock = lc_socket_new(lctx); if (!test_assert(sock != NULL, "lc_socket_new() (send thread)")) goto err_lc_ctx_free; chan = lc_channel_new(lctx, channel_name); if (!test_assert(chan != NULL, "lc_channel_new() (send thread)")) goto err_lc_ctx_free; rc = lc_channel_bind(sock, chan); if (!test_assert(rc == 0, "lc_channel_bind()")) goto err_lc_ctx_free; rc = lc_socket_loop(sock, 1); if (!test_assert(rc == 0, "lc_socket_loop()")) goto err_lc_ctx_free; /* start listening threads */ sem_init(&sem, 0, 0); for (int i = 0; i < ifcount; i++) { pthread_create(&tid[i], NULL, &thread_listen, &ifxa[i]); } /* wait for receiver threads to be ready */ for (int i = 0; i < ifcount; i++) sem_wait(&sem); test_log("all receivers ready\n"); /* Send one packet (with loopback set) */ byt = lc_channel_send(chan, name, sizeof name, 0); test_assert(byt == sizeof name, "%zi bytes sent", byt); /* Ensure packet is received by all interfaces */ struct timespec ts; clock_gettime(CLOCK_REALTIME, &ts); ts.tv_sec += TIMEOUT_SECONDS; for (int i = 0; i < ifcount; i++) { if (!test_assert(sem_timedwait(&sem, &ts) == 0, "timeout")) { break; } } for (int i = 0; i < ifcount; i++) { pthread_cancel(tid[i]); pthread_join(tid[i], NULL); } sem_destroy(&sem); err_lc_ctx_free: lc_ctx_free(lctx); return test_status; } librecast/test/0000-0064.c000066400000000000000000000037171502456746400151440ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2023-2024 Brett Sheffield */ /* mdex symlink */ #include "test.h" #include "testdata.h" #include #include #include #define TEST_SIZE 1024 * 1024 + 5 /* nice powers of two hide bugs - ensure test size is odd */ static_assert(TEST_SIZE % 2, "TEST_SIZE must be an odd number"); int main(void) { struct stat sb; char src[] = "0000-0064.src.tmp.XXXXXX"; char dst[] = "0000-0064.dst.tmp.XXXXXX"; unsigned char alias[HASHSIZE]; mdex_t *mdex; mtree_t mtree = {0}; mdex_entry_t entry = {0}; size_t off = 0; int fds, rc; test_name("mdex_addfile() (symlink)"); /* create test file */ fds = test_data_file(src, TEST_SIZE, TEST_TMP | TEST_RND); test_assert(fds != -1, "test_data_file()"); if (fds == -1) goto exit_0; test_assert(test_data_size(src, TEST_SIZE) == 0, "source exists and is correct size"); off = strlen(src) - 6; memcpy(dst + off, src + off, 6); /* create dst as symlink to src */ test_log("creating symlink '%s' => '%s'\n", dst, src); rc = symlink(src, dst); if (!test_assert(rc == 0, "symlink(): %s", strerror(errno))) goto exit_0; if (!test_assert(lstat(dst, &sb) != -1, "stat symlink")) goto exit_0; mdex = mdex_init(0); rc = mtree_init(&mtree, TEST_SIZE); if (!test_assert(rc == 0, "mtree_init() returned %i", rc)) goto err_free_mdex; /* add our symlink to mdex */ rc = mdex_addfile(mdex, dst, NULL, MDEX_ALIAS); if (!test_assert(rc == 0, "mdex_addfile() returned %i", rc)) goto err_free_mtree; /* test root hash is in index */ mdex_tree_hash_sb(alias, sizeof alias, NULL, 0, &sb, dst); test_log("fetching root hash\n"); hash_hex_debug(stderr, alias, HASHSIZE); rc = mdex_get(mdex, alias, HASHSIZE, &entry); test_assert(rc == 0, "root hash found"); err_free_mtree: mtree_free(&mtree); err_free_mdex: mdex_free(mdex); close(fds); unlink(dst); unlink(src); exit_0: return test_status; } librecast/test/0000-0065.c000066400000000000000000000102321502456746400151330ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2023 Brett Sheffield */ #include "testnet.h" #include "testdata.h" #include #include #include #include #include #include #include #define TEST_CHECK 0 #define TIMEOUT_SECONDS 5 #define TEST_SIZE 1024 * 100 + 5 /* nice powers of two hide bugs - ensure test size is odd */ static_assert(TEST_SIZE % 2, "TEST_SIZE must be an odd number"); static sem_t sem_recv; struct pkg_s { char *dst; uint8_t *hash; }; void *thread_recv(void *arg) { struct pkg_s *pkg = (struct pkg_s *)arg; lc_ctx_t *lctx = lc_ctx_new(); pthread_cleanup_push((void (*)(void *))lc_ctx_free, lctx); hash_hex_debug(stderr, pkg->hash, HASHSIZE); lc_syncfile(lctx, pkg->hash, pkg->dst, NULL, NULL, NULL, 0); pthread_cleanup_pop(1); /* lc_ctx_free */ sem_post(&sem_recv); return NULL; } int main(void) { #if HAVE_MLD struct stat sb; char src[] = "0000-0065.src.tmp.XXXXXX"; char lnk[] = "0000-0065.src.tmp.XXXXXX"; char dst[] = "0000-0065.dst.tmp.XXXXXX"; unsigned char root[HASHSIZE]; mdex_t *mdex; lc_ctx_t *lctx; lc_share_t *share; pthread_t tid_recv; struct pkg_s pkg_recv = {0}; struct timespec timeout = {0}; struct stat dsb = {0}; char buf[32]; ssize_t byt; size_t off; int fds, rc; test_cap_require(CAP_NET_ADMIN); test_name("lc_syncfile() (symlink)"); test_require_net(TEST_NET_BASIC); /* create test file */ fds = test_data_file(src, TEST_SIZE, TEST_TMP | TEST_RND); test_assert(fds != -1, "test_data_file()"); if (fds == -1) goto exit_0; test_assert(test_data_size(src, TEST_SIZE) == 0, "source exists and is correct size"); test_assert(stat(src, &sb) != -1, "stat source file"); /* create symlink (use mkstemp to create name so we get the usual format) */ rc = mkstemp(lnk); /* generate temp filename */ if (!test_assert(rc != -1, "mkstemp: %s", lnk)) { perror("mkstemp"); goto exit_0; } rc = unlink(lnk); /* delete the file - we don't need it */ if (!test_assert(rc == 0, "unlink: %s", lnk)) goto exit_0; rc = symlink(src, lnk); /* create symlink to src */ if (!test_assert(rc == 0, "symlink")) goto exit_0; /* set destination filename with same last 6 bytes as src */ off = strlen(src) - 6; memcpy(dst + off, src + off, 6); #if TEST_CHECK /* test the test */ char *cmd; rc = snprintf(NULL, 0, "ln -s %s %s", src, dst); assert(rc != -1); rc++; cmd = malloc(rc); snprintf(cmd, rc, "ln -s %s %s", src, dst); rc = system(cmd); test_assert(rc == 0, "system(%s)", cmd); #else /* add test data to index */ mdex = mdex_init(0); rc = mdex_addfile(mdex, lnk, NULL, 0); test_assert(rc == 0, "mdex_addfile() returned %i", rc); /* ensure root hash is in mdex */ if (!test_assert(lstat(lnk, &sb) != -1, "stat symlink")) goto exit_0; mdex_tree_hash_sb(root, sizeof root, NULL, 0, &sb, lnk); rc = mdex_get(mdex, root, sizeof root, NULL); test_assert(rc == 0, "root hash in mdex"); /* share the mdex */ lctx = lc_ctx_new(); share = lc_share(lctx, mdex, 0, NULL, NULL, LC_SHARE_LOOPBACK); test_assert(share != NULL, "lc_share()"); /* sync files */ sem_init(&sem_recv, 0, 0); pkg_recv.dst = dst; pkg_recv.hash = root; pthread_create(&tid_recv, NULL, thread_recv, &pkg_recv); clock_gettime(CLOCK_REALTIME, &timeout); timeout.tv_sec += TIMEOUT_SECONDS; if ((rc = sem_timedwait(&sem_recv, &timeout)) == -1 && errno == ETIMEDOUT) { pthread_cancel(tid_recv); } test_assert(rc == 0, "timeout waiting for recv thread"); pthread_join(tid_recv, NULL); #endif rc = lstat(dst, &dsb); test_assert(rc == 0, "lstat() %s", dst); if (!test_assert(S_ISLNK(dsb.st_mode), "S_ISLNK()")) goto exit_0; byt = readlink(dst, buf, sizeof buf); if (!test_assert((size_t)byt == strlen(src), "readlink returned correct length")) goto exit_0; test_log("buf (link target): '%.*s'\n", (int)byt, buf); test_assert(!strncmp(src, buf, byt), "link target points to src"); #if !TEST_CHECK /* clean up */ sem_destroy(&sem_recv); lc_unshare(share); lc_ctx_free(lctx); mdex_free(mdex); close(fds); #endif unlink(dst); unlink(src); exit_0: return test_status; #else return test_skip("lc_syncfile()"); #endif } librecast/test/0000-0066.c000066400000000000000000000033421502456746400151400ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2024 Brett Sheffield */ /* test thread safety of context API calls * run with CFLAGS="-fsanitize=thread" */ #include "test.h" #include #include #include #include #include static int nthreads = 3; static sem_t sem; void *thread_start(void *arg) { lc_ctx_t *lctx = (lc_ctx_t *)arg; sem_wait(&sem); if (lctx) { /* touch ctx */ test_log("reading from ctx->readers = %i\n", aload(&lctx->readers)); /* release */ test_log("calling lc_ctx_release()\n"); lc_ctx_release(lctx); } return arg; } void *thread_ctx_del(void *arg) { lc_ctx_t *lctx = (lc_ctx_t *)arg; sem_wait(&sem); test_log("%s() calling lc_ctx_free()\n", __func__); lc_ctx_free(lctx); return NULL; } int main(void) { pthread_t tid[nthreads]; lc_ctx_t *lctx; int rc; test_name("lc_ctx_acquire() / lc_ctx_release()"); /* create a Librecast Context */ lctx = lc_ctx_new(); if (!test_assert(lctx != NULL, "lc_ctx_new()")) return test_status; /* start some threads */ sem_init(&sem, 0, 0); /* use a semaphore to sync thread start */ for (int i = 0; i < nthreads - 1; i++) { rc = pthread_create(&tid[i], NULL, &thread_start, lc_ctx_acquire(lctx)); if (!test_assert(rc == 0, "pthread_create: %i", i)) { nthreads = i; break; } } rc = pthread_create(&tid[nthreads - 1], NULL, &thread_ctx_del, lctx); if (!test_assert(rc == 0, "pthread_create: %i", nthreads - 1)) { nthreads--; } for (int i = 0; i < nthreads; i++) sem_post(&sem); /* release the threads */ /* clean up */ for (int i = 0; i < nthreads; i++) { pthread_join(tid[i], NULL); } sem_destroy(&sem); return test_status; } librecast/test/0000-0067.c000066400000000000000000000037171502456746400151470ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2024 Brett Sheffield */ /* test thread safety of socket API calls * run with CFLAGS="-fsanitize=thread" */ #define _GNU_SOURCE /* gettid(2) */ #include "test.h" #include #include #include #include #include #include #ifndef gettid # define gettid() 0 #endif static int nthreads = 2; static int iterations = 2; static sem_t sem; /* * We create multiple threads running this function. * All have a pointer to the same lc_ctx_t. * They each create a socket, access it, and free it. * There MUST be no races between threads, as the sockets are completely * independent. The only shared memory is the ctx and ctx->sock_list */ void *thread_start(void *arg) { pid_t tid = gettid(); lc_ctx_t *lctx = (lc_ctx_t *)arg; lc_socket_t *sock; sem_wait(&sem); for (int i = 0; i < iterations; i++) { sock = lc_socket_new(lctx); test_log("[%i]: new sock %p\n", tid, (void *)sock); test_log("[%i]: sock->readers = %i\n", tid, aload(&sock->readers)); test_log("[%i]: closing sock %p\n", tid, (void *)sock); lc_socket_close(sock); } return arg; } int main(void) { pthread_t tid[nthreads]; lc_ctx_t *lctx; int rc; test_name("lc_socket_acquire() / lc_socket_release()"); /* create a Librecast Context */ lctx = lc_ctx_new(); if (!test_assert(lctx != NULL, "lc_ctx_new()")) return test_status; /* start some threads */ sem_init(&sem, 0, 0); /* use a semaphore to sync thread start */ for (int i = 0; i < nthreads; i++) { rc = pthread_create(&tid[i], NULL, &thread_start, lctx); if (!test_assert(rc == 0, "pthread_create: %i", i)) { nthreads = i; break; } } for (int i = 0; i < nthreads; i++) sem_post(&sem); /* release the threads */ /* clean up */ for (int i = 0; i < nthreads; i++) { pthread_join(tid[i], NULL); } sem_destroy(&sem); lc_ctx_free(lctx); return test_status; } librecast/test/0000-0068.c000066400000000000000000000032621502456746400151430ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2024 Brett Sheffield */ /* test thread safety of channel API calls * run with CFLAGS="-fsanitize=thread" */ #define _GNU_SOURCE /* gettid(2) */ #include "test.h" #include #include #include #include #include #include #ifndef gettid # define gettid() 0 #endif static int nthreads = 2; static int iterations = 2; static sem_t sem; void *thread_start(void *arg) { pid_t tid = gettid(); lc_ctx_t *lctx = (lc_ctx_t *)arg; lc_channel_t *chan; sem_wait(&sem); for (int i = 0; i < iterations; i++) { chan = lc_channel_new(lctx, "atomic"); test_log("[%i]: new chan %p\n", tid, (void *)chan); test_log("[%i]: chan->readers = %i\n", tid, aload(&chan->readers)); test_log("[%i]: closing chan %p\n", tid, (void *)chan); lc_channel_free(chan); } return arg; } int main(void) { pthread_t tid[nthreads]; lc_ctx_t *lctx; int rc; test_name("lc_channel_acquire() / lc_channel_release()"); /* create a Librecast Context */ lctx = lc_ctx_new(); if (!test_assert(lctx != NULL, "lc_ctx_new()")) return test_status; /* start some threads */ sem_init(&sem, 0, 0); /* use a semaphore to sync thread start */ for (int i = 0; i < nthreads; i++) { rc = pthread_create(&tid[i], NULL, &thread_start, lctx); if (!test_assert(rc == 0, "pthread_create: %i", i)) { nthreads = i; break; } } for (int i = 0; i < nthreads; i++) sem_post(&sem); /* release the threads */ /* clean up */ for (int i = 0; i < nthreads; i++) { pthread_join(tid[i], NULL); } sem_destroy(&sem); lc_ctx_free(lctx); return test_status; } librecast/test/0000-0069.c000066400000000000000000000113121502456746400151370ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2017-2024 Brett Sheffield */ #include "testnet.h" #include #include #include #include #include #include #include #include #include #undef TESTDEBUG #ifdef TESTDEBUG # define PKTS 10 # define PKTSZ 4 #else # define PKTS 20 # define PKTSZ 1024 #endif #define WAITS 2 #ifdef HAVE_LIBLCRQ static const size_t SZ = PKTS * PKTSZ + 5; enum { TID_SEND, TID_RECV }; static char channel_name[] = "0000-0039"; static sem_t receiver_ready, timeout; #ifdef TESTDEBUG static void dumppkt(uint8_t *pkt, int haseq) { uint16_t seq; uint8_t *dat = pkt; if (haseq) { dat += sizeof seq; seq = ntohs(*(uint16_t *)pkt); fprintf(stderr, "%u: ", seq); } else fprintf(stderr, " "); for (size_t z = 0; z < PKTSZ * 8; z++) { if (isset(dat, z)) putc('1', stderr); else putc('0', stderr); } putc('\n', stderr); } static void dump_bufs(uint8_t buf[2][SZ]) { for (size_t p = 0; p < PKTS; p++) { fprintf(stderr, "%zu: ", p); for (int i = 0; i < 2; i++) { for (size_t z = 0; z < PKTSZ * 8; z++) { uint8_t *b = buf[i]; if (isset(b, p * PKTSZ * 8 + z)) putc('1', stderr); else putc('0', stderr); } putc(' ', stderr); } putc('\n', stderr); } putc('\n', stderr); } #endif static void generate_source_data(uint8_t *buf, size_t sz) { ssize_t rc; int f; f = open("/dev/urandom", O_RDONLY); if (f == -1) return; rc = read(f, buf, sz); test_assert(rc == (ssize_t)sz, "%zi random bytes read", rc); close(f); } static void *recv_data_fec(void *arg) { uint8_t *buf = (uint8_t *)arg; ssize_t rc; lc_ctx_t *lctx = lc_ctx_new(); lc_socket_t * sock = lc_socket_new(lctx); lc_channel_t * chan = lc_channel_new(lctx, channel_name); memset(buf, 0, SZ); /* clear receive buffer */ lc_channel_bind(sock, chan); lc_channel_join(chan); lc_channel_coding_set(chan, LC_CODE_FEC_RQ); sem_post(&receiver_ready); rc = lc_channel_recv(chan, buf, SZ, 0); test_log("lc_channel_recv returned %zi\n", rc); test_assert(rc >= (ssize_t)SZ, "data received %zi/%zu bytes", rc, SZ); lc_channel_part(chan); lc_ctx_free(lctx); sem_post(&timeout); return arg; } static void *send_data_fec(void *arg) { uint8_t *buf = (uint8_t *)arg; struct iovec iov = { .iov_base = buf, .iov_len = SZ }; struct msghdr msg = { .msg_iov = &iov, .msg_iovlen = 1 }; lc_ctx_t *lctx = lc_ctx_new(); lc_socket_t * sock = lc_socket_new(lctx); lc_channel_t * chan = lc_channel_new(lctx, channel_name); rq_t *rq; ssize_t rc; size_t byt = 0; lc_socket_loop(sock, 1); lc_channel_bind(sock, chan); lc_channel_coding_set(chan, LC_CODE_FEC_RQ); test_log("sending data with FEC\n"); sem_wait(&receiver_ready); rc = lc_channel_sendmsg(chan, &msg, 0); test_assert(rc > 0, "lc_channel_send encoded data, returned %zi", rc); if (rc == -1) goto err_ctx_free; byt = rc; rq = lc_channel_rq(chan); if (!test_assert(rq != NULL, "lc_channel_rq()")) goto err_ctx_free; /* Send packets. Drop packet 3 */ int pkts = rq_KP(rq) + RQ_OVERHEAD * 2; test_log("sending %u packets\n", pkts); for (int i = 1; i < pkts; i++) { int flags = (i == 3) ? MSG_DROP : 0; rc = lc_channel_sendmsg(chan, NULL, flags); test_assert(rc > 0, "lc_channel_sendmsg encoded data, returned %zi", rc); if (rc > 0) byt += rc; } test_assert(byt >= SZ, "data sent %zi bytes (buffer = %zu)", byt, SZ); err_ctx_free: lc_ctx_free(lctx); return arg; } #endif int main(void) { char name[] = "lc_channel_sendmsg() / lc_channel_recv() - RaptorQ (RFC 6330)"; #ifndef HAVE_LIBLCRQ return test_skip(name); #else pthread_t tid[2]; uint8_t *buf[2]; struct timespec ts; int rc; test_name(name); test_require_net(TEST_NET_BASIC); buf[TID_SEND] = malloc(SZ); assert(buf[TID_SEND]); buf[TID_RECV] = malloc(SZ); assert(buf[TID_RECV]); memset(buf[0], 0, SZ); memset(buf[1], 0, SZ); sem_init(&timeout, 0, 0); sem_init(&receiver_ready, 0, 0); generate_source_data(buf[TID_SEND], SZ); test_assert(memcmp(buf[TID_RECV], buf[TID_SEND], SZ), "buffer differ before sync"); pthread_create(&tid[TID_SEND], NULL, &send_data_fec, buf[TID_SEND]); pthread_create(&tid[TID_RECV], NULL, &recv_data_fec, buf[TID_RECV]); clock_gettime(CLOCK_REALTIME, &ts); ts.tv_sec += WAITS; rc = sem_timedwait(&timeout, &ts); test_assert(rc == 0, "timeout"); pthread_cancel(tid[TID_RECV]); pthread_join(tid[TID_RECV], NULL); pthread_join(tid[TID_SEND], NULL); sem_destroy(&receiver_ready); sem_destroy(&timeout); if (!rc) test_assert(!memcmp(buf[TID_RECV], buf[TID_SEND], SZ), "send buffer matches received"); #ifdef TESTDEBUG dump_bufs(buf); #endif free(buf[TID_SEND]); free(buf[TID_RECV]); return test_status; #endif } librecast/test/0000-0070.c000066400000000000000000000041741502456746400151370ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2024 Brett Sheffield */ #include "testnet.h" #include #include #include #define WAITS 1 static char channel_name[] = "0000-0070"; static sem_t sem; static ssize_t bytes = -1; static void *listen_thread(void *arg) { lc_ctx_t * lctx; lc_socket_t * sock; lc_channel_t * chan; struct iovec iov; struct msghdr msg = {0}; lctx = lc_ctx_new(); sock = lc_socket_new(lctx); chan = lc_channel_new(lctx, channel_name); iov.iov_base = arg; iov.iov_len = BUFSIZ; msg.msg_iov = &iov; msg.msg_iovlen = 1; lc_channel_bind(sock, chan); lc_channel_join(chan); sem_post(&sem); /* tell send thread we're ready */ bytes = lc_channel_recvmsg(chan, &msg, 0); if (bytes == -1) perror("lc_channel_recvmsg"); sem_post(&sem); /* tell send thread we're done */ lc_ctx_free(lctx); return arg; } int main(void) { lc_ctx_t * lctx; lc_socket_t * sock; lc_channel_t * chan; pthread_attr_t attr = {0}; pthread_t thread; struct timespec ts; char buf[] = "liberté"; char recvbuf[BUFSIZ] = ""; struct iovec iov; struct msghdr msg = {0}; test_name("lc_channel_sendmsg() / lc_channel_recvmsg()"); test_require_net(TEST_NET_BASIC); sem_init(&sem, 0, 0); pthread_attr_init(&attr); pthread_create(&thread, &attr, &listen_thread, &recvbuf); pthread_attr_destroy(&attr); sem_wait(&sem); /* recv thread is ready */ lctx = lc_ctx_new(); sock = lc_socket_new(lctx); chan = lc_channel_new(lctx, channel_name); iov.iov_base = buf; iov.iov_len = strlen(buf) + 1; msg.msg_iov = &iov; msg.msg_iovlen = 1; lc_socket_loop(sock, 1); lc_channel_bind(sock, chan); lc_channel_sendmsg(chan, &msg, 0); lc_ctx_free(lctx); test_assert(!clock_gettime(CLOCK_REALTIME, &ts), "clock_gettime()"); ts.tv_sec += WAITS; test_assert(!sem_timedwait(&sem, &ts), "timeout"); sem_timedwait(&sem, &ts); sem_destroy(&sem); pthread_cancel(thread); pthread_join(thread, NULL); test_assert(bytes == (ssize_t)iov.iov_len, "received %zi bytes, expected %zu", bytes, iov.iov_len); test_expect(buf, recvbuf); return test_status; } librecast/test/0000-0071.c000066400000000000000000000112011502456746400151250ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2024 Brett Sheffield */ #include "testnet.h" #include #include #include #include #include #include #include #include #include #undef TESTDEBUG #ifdef TESTDEBUG # define PKTS 10 # define PKTSZ 4 #else # define PKTS 20 # define PKTSZ 1024 #endif #define WAITS 20 #ifdef HAVE_LIBLCRQ enum { TID_SEND, TID_RECV }; static const size_t SZ = PKTS * PKTSZ + 5; static char channel_name[] = "0000-0039"; static sem_t receiver_ready, timeout; #ifdef TESTDEBUG static void dumppkt(uint8_t *pkt, int haseq) { uint16_t seq; uint8_t *dat = pkt; if (haseq) { dat += sizeof seq; seq = ntohs(*(uint16_t *)pkt); fprintf(stderr, "%u: ", seq); } else fprintf(stderr, " "); for (size_t z = 0; z < PKTSZ * 8; z++) { if (isset(dat, z)) putc('1', stderr); else putc('0', stderr); } putc('\n', stderr); } static void dump_bufs(uint8_t buf[2][SZ]) { for (size_t p = 0; p < PKTS; p++) { fprintf(stderr, "%zu: ", p); for (int i = 0; i < 2; i++) { for (size_t z = 0; z < PKTSZ * 8; z++) { uint8_t *b = buf[i]; if (isset(b, p * PKTSZ * 8 + z)) putc('1', stderr); else putc('0', stderr); } putc(' ', stderr); } putc('\n', stderr); } putc('\n', stderr); } #endif static void generate_source_data(uint8_t *buf, size_t sz) { ssize_t rc; int f; f = open("/dev/urandom", O_RDONLY); if (f == -1) return; rc = read(f, buf, sz); test_assert(rc == (ssize_t)sz, "%zi random bytes read", rc); close(f); } static void *recv_data_fec(void *arg) { uint8_t *buf = (uint8_t *)arg; struct iovec iov = { .iov_base = buf, .iov_len = SZ }; struct msghdr msg = { .msg_iov = &iov, .msg_iovlen = 1 }; ssize_t rc; lc_ctx_t *lctx = lc_ctx_new(); lc_socket_t * sock = lc_socket_new(lctx); lc_channel_t * chan = lc_channel_new(lctx, channel_name); memset(buf, 0, SZ); /* clear receive buffer */ lc_channel_bind(sock, chan); lc_channel_join(chan); lc_channel_coding_set(chan, LC_CODE_FEC_RQ); sem_post(&receiver_ready); rc = lc_channel_recvmsg(chan, &msg, 0); test_log("lc_channel_recvmsg returned %zi\n", rc); test_assert(rc >= (ssize_t)SZ, "data received %zi/%zu bytes", rc, SZ); lc_channel_part(chan); lc_ctx_free(lctx); sem_post(&timeout); return arg; } static void *send_data_fec(void *arg) { uint8_t *buf = (uint8_t *)arg; lc_ctx_t *lctx = lc_ctx_new(); lc_socket_t * sock = lc_socket_new(lctx); lc_channel_t * chan = lc_channel_new(lctx, channel_name); rq_t *rq; ssize_t rc; size_t byt = 0; lc_socket_loop(sock, 1); lc_channel_bind(sock, chan); lc_channel_coding_set(chan, LC_CODE_FEC_RQ); test_log("sending data with FEC\n"); sem_wait(&receiver_ready); rc = lc_channel_send(chan, buf, SZ, 0); test_assert(rc > 0, "lc_channel_send encoded data, returned %zi", rc); if (rc == -1) goto err_ctx_free; byt = rc; rq = lc_channel_rq(chan); /* Send packets. Drop packet 3 */ int pkts = rq_KP(rq) + RQ_OVERHEAD * 2; test_log("sending %u packets\n", pkts); for (int i = 1; i < pkts; i++) { int flags = (i == 3) ? MSG_DROP : 0; rc = lc_channel_send(chan, NULL, 0, flags); test_assert(rc > 0, "lc_channel_send encoded data, returned %zi", rc); if (rc > 0) byt += rc; } test_assert(byt >= SZ, "data sent %zi bytes (buffer = %zu)", byt, SZ); err_ctx_free: lc_ctx_free(lctx); return arg; } #endif int main(void) { char name[] = "lc_channel_send() / lc_channel_recvmsg() - RaptorQ (RFC 6330)"; #ifndef HAVE_LIBLCRQ return test_skip(name); #else pthread_t tid[2]; uint8_t *buf[2]; struct timespec ts; int rc; test_name(name); test_require_net(TEST_NET_BASIC); buf[TID_SEND] = malloc(SZ); assert(buf[TID_SEND]); buf[TID_RECV] = malloc(SZ); assert(buf[TID_RECV]); memset(buf[0], 0, SZ); memset(buf[1], 0, SZ); sem_init(&timeout, 0, 0); sem_init(&receiver_ready, 0, 0); generate_source_data(buf[TID_SEND], SZ); test_assert(memcmp(buf[TID_RECV], buf[TID_SEND], SZ), "buffer differ before sync"); pthread_create(&tid[TID_SEND], NULL, &send_data_fec, buf[TID_SEND]); pthread_create(&tid[TID_RECV], NULL, &recv_data_fec, buf[TID_RECV]); clock_gettime(CLOCK_REALTIME, &ts); ts.tv_sec += WAITS; rc = sem_timedwait(&timeout, &ts); test_assert(rc == 0, "timeout"); pthread_cancel(tid[TID_RECV]); pthread_join(tid[TID_RECV], NULL); pthread_join(tid[TID_SEND], NULL); sem_destroy(&receiver_ready); sem_destroy(&timeout); if (!rc) test_assert(!memcmp(buf[TID_RECV], buf[TID_SEND], SZ), "send buffer matches received"); #ifdef TESTDEBUG dump_bufs(buf); #endif free(buf[TID_SEND]); free(buf[TID_RECV]); return test_status; #endif } librecast/test/0000-0072.c000066400000000000000000000061241502456746400151360ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2024 Brett Sheffield */ /* send some msgs, receive using lc_socket_recvmmsg() */ #include "testnet.h" #include #include #include #define WAITS 2 #define VLEN 42 /* number of msgs to send/recv */ static char channel_name[] = "0000-0072"; static sem_t sem; static volatile ssize_t bytes; static char recvbuf[VLEN][BUFSIZ]; static void *listen_thread(void *arg) { lc_ctx_t * lctx; lc_socket_t * sock; lc_channel_t * chan; struct iovec iov[VLEN]; struct mmsghdr msgs[VLEN]; int rc; lctx = lc_ctx_new(); sock = lc_socket_new(lctx); chan = lc_channel_new(lctx, channel_name); memset(msgs, 0, sizeof msgs); for (int i = 0; i < VLEN; i++) { iov[i].iov_base = recvbuf[i]; iov[i].iov_len = BUFSIZ; msgs[i].msg_hdr.msg_iov = &iov[i]; msgs[i].msg_hdr.msg_iovlen = 1; } lc_channel_bind(sock, chan); lc_channel_join(chan); sem_post(&sem); /* tell send thread we're ready */ test_log("receiving on fd %i\n", lc_socket_raw(sock)); rc = lc_socket_recvmmsg(sock, msgs, VLEN, 0, NULL); if (rc == -1) { perror("lc_socket_recvmmsg"); } else { test_assert(rc == VLEN, "received %i/%i msgs", rc, VLEN); for (int i = 0; i < rc; i++) { bytes += msgs[i].msg_len; test_log("reporting %u bytes\n", msgs[i].msg_len); } } sem_post(&sem); /* tell send thread we're done */ lc_ctx_free(lctx); return arg; } int main(void) { lc_ctx_t * lctx; lc_socket_t * sock; lc_channel_t * chan; pthread_t thread; struct timespec ts; char buf[] = "liberté"; struct iovec iov; struct msghdr msg = {0}; ssize_t rc; test_name("lc_channel_sendmsg() / lc_socket_recvmmsg() - multiple message recv"); test_require_net(TEST_NET_BASIC); sem_init(&sem, 0, 0); memset(recvbuf, 0, sizeof recvbuf); /* set up Librecast objects */ lctx = lc_ctx_new(); sock = lc_socket_new(lctx); chan = lc_channel_new(lctx, channel_name); lc_socket_loop(sock, 1); lc_channel_bind(sock, chan); /* start listen thread */ pthread_create(&thread, NULL, &listen_thread, NULL); sem_wait(&sem); /* listen thread is ready */ /* send some messages */ iov.iov_base = buf; iov.iov_len = strlen(buf) + 1; msg.msg_iov = &iov; msg.msg_iovlen = 1; test_log("sending on fd %i\n", lc_socket_raw(sock)); for (int i = 0; i < VLEN; i++) { rc = lc_channel_sendmsg(chan, &msg, 0); if (!test_assert(rc != -1, "lc_channel_sendmsg()")) { perror("lc_channel_sendmsg"); break; } test_assert(rc == sizeof buf, "lc_channel_sendmsg %zi bytes sent", rc); } /* wait for listen thread */ test_assert(!clock_gettime(CLOCK_REALTIME, &ts), "clock_gettime()"); ts.tv_sec += WAITS; if (!test_assert(sem_timedwait(&sem, &ts) == 0, "timeout")) { pthread_cancel(thread); } pthread_join(thread, NULL); sem_destroy(&sem); lc_ctx_free(lctx); size_t received = bytes; size_t expected = sizeof buf * VLEN; test_assert(received == expected, "received %zi bytes, expected %zu", expected, received); for (int i = 0; i < VLEN; i++) { test_expect(buf, recvbuf[i]); } return test_status; } librecast/test/0000-0073.c000066400000000000000000000012341502456746400151340ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2024 Brett A C Sheffield */ #include "test.h" #include int main(void) { char name[] = "lc_socket_ctx() - return context for socket"; lc_ctx_t *lctx, *ctx_check; lc_socket_t *sock; test_name(name); lctx = lc_ctx_new(); if (!test_assert(lctx != NULL, "lc_ctx_new()")) return test_status; sock = lc_socket_new(lctx); if (!test_assert(sock != NULL, "lc_socket_new()")) goto err_ctx_free; ctx_check = lc_socket_ctx(sock); test_assert(ctx_check == lctx, "lc_socket_ctx() returns ctx"); err_ctx_free: lc_ctx_free(lctx); return test_status; } librecast/test/0000-0074.c000066400000000000000000000106041502456746400151360ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2025 Brett A C Sheffield */ /* * https://todo.sr.ht/~librecast/librecast/121 * * When calling lc_channel_recv(3) with multiple channels bound to a socket, * return an error code when a packet for a different channel is received. */ #include "test.h" #include "testnet.h" #include #include #include #include #define WAITS 20 #define PAYLOADMAX 1024 #define CHANNELS 2 enum { TID_SEND, TID_RECV }; enum { CHAN_WRONG, CHAN_RIGHT, }; static sem_t receiver_ready, timeout; static unsigned int ifidx; static lc_channel_t *create_and_bind_channel(lc_ctx_t *lctx, lc_socket_t *sock, int channel_number) { lc_channel_t *chan; char chanstr[2]; int rc; assert(channel_number < 10 && channel_number >= 0); sprintf(chanstr, "%d", channel_number); chan = lc_channel_new(lctx, chanstr); if (!chan) return NULL; rc = lc_channel_bind(sock, chan); if (!test_assert(rc == 0, "lc_channel_bind() %s", chanstr)) return NULL; return chan; } static void *recv_data(void * arg) { char *buf = (char *)arg; lc_ctx_t *lctx; lc_socket_t *sock; lc_channel_t *chan[CHANNELS]; ssize_t byt; int rc; lctx = lc_ctx_new(); if (!lctx) return NULL; sock = lc_socket_new(lctx); if (!sock) goto err_ctx_free; if (lc_socket_bind(sock, ifidx) == -1) goto err_ctx_free; lc_socket_loop(sock, 1); for (int i = 0; i < CHANNELS; i++) { chan[i] = create_and_bind_channel(lctx, sock, i); if (!chan[i]) goto err_ctx_free; rc = lc_channel_join(chan[i]); if (!test_assert(rc == 0, "lc_channel_join() %i", i)) goto err_ctx_free; } sem_post(&receiver_ready); /* recv from "RIGHT" channel, expect error as data will be for "WRONG" */ byt = lc_channel_recv(chan[CHAN_RIGHT], buf, PAYLOADMAX, 0); test_assert(byt == -1, "lc_channel_recv() - error expected"); byt = lc_channel_recv(chan[CHAN_RIGHT], buf, PAYLOADMAX, 0); test_assert(byt == PAYLOADMAX, "lc_channel_recv() - data received"); /* now set MSG_DROP and repeat, this time we won't see the "WRONG" packet */ sem_post(&receiver_ready); byt = lc_channel_recv(chan[CHAN_RIGHT], buf, PAYLOADMAX, MSG_DROP); test_assert(byt == PAYLOADMAX, "lc_channel_recv() - data received (MSG_DROP flag)"); sem_post(&timeout); err_ctx_free: lc_ctx_free(lctx); return arg; } static void *send_data(void * arg) { char *buf = (char *)arg; lc_ctx_t *lctx; lc_socket_t *sock; lc_channel_t *chan[CHANNELS]; ssize_t byt; lctx = lc_ctx_new(); if (!lctx) return NULL; sock = lc_socket_new(lctx); if (!sock) goto err_ctx_free; if (lc_socket_bind(sock, ifidx) == -1) goto err_ctx_free; lc_socket_loop(sock, 1); for (int i = 0; i < CHANNELS; i++) { chan[i] = create_and_bind_channel(lctx, sock, i); if (!chan[i]) goto err_ctx_free; } /* run test twice, recv thread will set MSG_DROP on second run */ for (int i = 0; i < 2; i++) { sem_wait(&receiver_ready); /* send on "WRONG" channel first */ byt = lc_channel_send(chan[CHAN_WRONG], buf, PAYLOADMAX, 0); test_assert(byt == PAYLOADMAX, "lc_channel_recv() - data sent to WRONG channel"); /* send on "RIGHT" channel now */ byt = lc_channel_send(chan[CHAN_RIGHT], buf, PAYLOADMAX, 0); test_assert(byt == PAYLOADMAX, "lc_channel_recv() - data sent to RIGHT channel"); } err_ctx_free: lc_ctx_free(lctx); return arg; } int main(void) { char name[] = "lc_channel_recv: multi-channel socket: error for wrong channel"; char buf[CHANNELS][PAYLOADMAX]; pthread_t tid[2]; struct timespec ts; int rc; test_name(name); test_require_net(TEST_NET_BASIC); ifidx = get_multicast_if(); if (!test_assert(ifidx > 0, "get_multicast_if()")) return test_status; sem_init(&timeout, 0, 0); sem_init(&receiver_ready, 0, 0); /* generate random data and clear recv buffer */ arc4random_buf(buf[TID_SEND], PAYLOADMAX); memset(buf[TID_RECV], 0, PAYLOADMAX); pthread_create(&tid[TID_SEND], NULL, &send_data, buf[TID_SEND]); pthread_create(&tid[TID_RECV], NULL, &recv_data, buf[TID_RECV]); clock_gettime(CLOCK_REALTIME, &ts); ts.tv_sec += WAITS; rc = sem_timedwait(&timeout, &ts); test_assert(rc == 0, "timeout"); pthread_cancel(tid[TID_RECV]); pthread_join(tid[TID_RECV], NULL); pthread_join(tid[TID_SEND], NULL); sem_destroy(&receiver_ready); sem_destroy(&timeout); rc = memcmp(buf[TID_RECV], buf[TID_SEND], PAYLOADMAX); test_assert(rc == 0, "recv and send buffers match"); return test_status; } librecast/test/0000-0075.c000066400000000000000000000146171502456746400151470ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2025 Brett A C Sheffield */ /* * generate random test payloads, each > 1500 (MTU) bytes * on the receiver: * - create a socket and bind some channels to it * - enable RaptorQ encoding on the channels * - join the channels * - recv data on the socket * * on the sender: * - enable RaptorQ encoding on the channels * - send symbols interleaved * * TEST: all payloads received and match */ #include "test.h" #ifdef HAVE_LIBLCRQ #include "testdata.h" #include "testnet.h" #include #include #include #include #define DO_INTERLEAVED 1 /* 1 => randomly interleave packets for different channels */ #define PAYLOADMAX 16384 /* maximum payload size */ #define PAYLOADMIN 1500 /* minimum payload size */ #define PAYLOADS 3 /* number of channels per socket */ #define WAITS 20 /* timeout (seconds) */ enum { TID_SEND, TID_RECV }; static sem_t receiver_ready, timeout; static int sz[PAYLOADS]; static unsigned int ifidx; static char srcdata[PAYLOADS][PAYLOADMAX]; static char dstdata[PAYLOADS][PAYLOADMAX]; static lc_channel_t *create_and_bind_channel(lc_ctx_t *lctx, lc_socket_t *sock, int channel_number) { lc_channel_t *chan; char chanstr[3]; int rc; assert(channel_number < 100 && channel_number >= 0); sprintf(chanstr, "%02d", channel_number); chan = lc_channel_new(lctx, chanstr); if (!chan) return NULL; rc = lc_channel_bind(sock, chan); if (!test_assert(rc == 0, "%s: lc_channel_bind()", chanstr)) return NULL; rc = lc_channel_coding_set(chan, LC_CODE_FEC_RQ); if (!test_assert(rc == LC_CODE_FEC_RQ, "%s: lc_channel_coding_set()", chanstr)) return NULL; return chan; } #if DO_INTERLEAVED static int alldone(int sent[PAYLOADS]) { for (int i = 0; i < PAYLOADS; i++) { if (sent[i]) return 0; } return -1; } #endif static void *send_data_fec(void *arg) { lc_ctx_t *lctx; lc_socket_t *sock; lc_channel_t *chan[PAYLOADS]; lctx = lc_ctx_new(); if (!lctx) goto err_exit; sock = lc_socket_new(lctx); if (!sock) goto err_ctx_free; if (lc_socket_bind(sock, ifidx) == -1) goto err_ctx_free; lc_socket_loop(sock, 1); lc_ctx_ratelimit(lctx, 1024 * 1024, -1); for (int i = 0; i < PAYLOADS; i++) { chan[i] = create_and_bind_channel(lctx, sock, i); if (!chan[i]) goto err_ctx_free; } test_log("waiting for receiver\n"); sem_wait(&receiver_ready); #if DO_INTERLEAVED /* send stuff, interleaved */ int sent[PAYLOADS]; /* encode payload and send first packet on each channel */ for (int i = 0; i < PAYLOADS; i++) { test_log("%d: attempting to send %i bytes\n", i, sz[i]); lc_channel_send(chan[i], srcdata[i], sz[i], 0); /* send first pkt */ /* packet loss might be quite high sending this much at once: * double the packets sent to compensate */ sent[i] = (rq_KP(lc_channel_rq(chan[i])) + RQ_OVERHEAD) * 2; } /* keep sending randomly on all channels until all minimum has been sent to all */ do { int p = arc4random_uniform(PAYLOADS); test_log("sending to channel %d\n", p); if (lc_channel_send(chan[p], NULL, 0, 0) == -1) { test_log("error sending to channel %d\n", p); break; } sent[p]--; } while (!alldone(sent)); #else /* interleaving disabled: send to each channel in order */ for (int i = 0; i < PAYLOADS; i++) { test_log("%d: attempting to send %i bytes\n", i, sz[i]); lc_channel_send(chan[i], srcdata[i], sz[i], 0); const int pkts = rq_KP(lc_channel_rq(chan[i])) + RQ_OVERHEAD * 2; test_log("%d: sending %u packets\n", i, pkts); for (int j = 1; j < pkts * 2; j++) { if (lc_channel_send(chan[i], NULL, 0, 0) == -1) break; } } #endif err_ctx_free: lc_ctx_free(lctx); err_exit: return arg; } static void *recv_data_fec(void *arg) { char buf[PAYLOADMAX]; lc_ctx_t *lctx; lc_socket_t *sock; lc_channel_t *chan[PAYLOADS]; lc_channel_t *dst = NULL; int rc; lctx = lc_ctx_new(); if (!lctx) goto err_exit; sock = lc_socket_new(lctx); if (!sock) goto err_ctx_free; if (lc_socket_bind(sock, ifidx) == -1) goto err_ctx_free; for (int i = 0; i < PAYLOADS; i++) { chan[i] = create_and_bind_channel(lctx, sock, i); if (!chan[i]) goto err_ctx_free; rc = lc_channel_join(chan[i]); if (!test_assert(rc == 0, "%02d: lc_channel_join()")) goto err_ctx_free; } sem_post(&receiver_ready); for (int i = 0; i < PAYLOADS; i++) { ssize_t byt = lc_socket_multi_recv(sock, buf, sizeof buf, 0, &dst); test_log("%zi byt recv'd\n", byt); test_log("dst = %p\n", (void *)dst); if (byt > 0) { /* copy data to correct buffer for dst channel */ for (int x = 0; x < PAYLOADS; x++) { test_log("[%d] = %p\n", x, (void *)chan[x]); if (dst == chan[x]) memcpy(dstdata[x], buf, byt); } } } err_ctx_free: lc_ctx_free(lctx); err_exit: sem_post(&timeout); return arg; } static void generate_source_data(int sz[PAYLOADS], char srcdata[PAYLOADS][PAYLOADMAX]) { for (int i = 0; i < PAYLOADS; i++) { sz[i] = arc4random_uniform(PAYLOADMAX - PAYLOADMIN) + PAYLOADMIN; arc4random_buf(srcdata[i], sz[i]); arc4random_buf(srcdata[i], sz[i]); test_log("generated %i bytes\n", sz[i]); } } #endif /* HAVE_LIBLCRQ */ int main(void) { char name[] = "multi-channel socket with RaptorQ encoding"; #ifndef HAVE_LIBLCRQ return test_skip(name); #else struct timespec ts; pthread_t tid[2]; int rc; test_name(name); test_require_net(TEST_NET_BASIC); ifidx = get_multicast_if(); generate_source_data(sz, srcdata); /* ensure buffers differ before sync */ for (int i = 0; i < PAYLOADS; i++) { memset(dstdata[i], 0, PAYLOADMAX); test_assert(memcmp(dstdata[i], srcdata[i], PAYLOADMAX) != 0, "payload %i differs", i); } sem_init(&timeout, 0, 0); sem_init(&receiver_ready, 0, 0); pthread_create(&tid[TID_SEND], NULL, &send_data_fec, srcdata); pthread_create(&tid[TID_RECV], NULL, &recv_data_fec, dstdata); clock_gettime(CLOCK_REALTIME, &ts); ts.tv_sec += WAITS; rc = sem_timedwait(&timeout, &ts); test_assert(rc == 0, "timeout"); pthread_cancel(tid[TID_SEND]); pthread_cancel(tid[TID_RECV]); pthread_join(tid[TID_RECV], NULL); pthread_join(tid[TID_SEND], NULL); sem_destroy(&receiver_ready); sem_destroy(&timeout); for (int i = 0; i < PAYLOADS; i++) { for (int j = 0; j < sz[i]; j++) { if (srcdata[i][j] == dstdata[i][j]) continue; test_assert(0, "%d: diff at %d / %d", i, j, sz[i]); break; } test_assert(memcmp(dstdata[i], srcdata[i], sz[i]) == 0, "payload %i matches", i); } return test_status; #endif } librecast/test/0000-0076.c000066400000000000000000000117031502456746400151410ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2025 Brett A C Sheffield */ /* * https://todo.sr.ht/~librecast/librecast/121 * * lc_socket_multi_recv(3) - same as lc_socket_recv(3), but returns destination channel in dst * */ #include "test.h" #include "testnet.h" #include #include #include #include #define WAITS 20 #define PAYLOADMAX 1024 #define CHANNELS 2 enum { TID_SEND, TID_RECV }; enum { CHAN_LEFT, CHAN_RIGHT, }; static sem_t receiver_ready, timeout; static unsigned int ifidx; static lc_channel_t *create_and_bind_channel(lc_ctx_t *lctx, lc_socket_t *sock, int channel_number) { lc_channel_t *chan; char chanstr[2]; int rc; assert(channel_number >= 0 && channel_number < CHANNELS); sprintf(chanstr, "%d", channel_number); chan = lc_channel_new(lctx, chanstr); if (!chan) return NULL; rc = lc_channel_bind(sock, chan); if (!test_assert(rc == 0, "lc_channel_bind() %s", chanstr)) return NULL; return chan; } static void *recv_data(void * arg) { char *buf = (char *)arg; lc_ctx_t *lctx; lc_socket_t *sock; lc_channel_t *chan[CHANNELS]; ssize_t byt; int rc; lctx = lc_ctx_new(); if (!lctx) return NULL; sock = lc_socket_new(lctx); if (!sock) goto err_ctx_free; if (lc_socket_bind(sock, ifidx) == -1) goto err_ctx_free; lc_socket_loop(sock, 1); for (int i = 0; i < CHANNELS; i++) { chan[i] = create_and_bind_channel(lctx, sock, i); if (!chan[i]) goto err_ctx_free; rc = lc_channel_join(chan[i]); if (!test_assert(rc == 0, "lc_channel_join() %i", i)) goto err_ctx_free; } /* recv from socket, expect data on LEFT channel */ sem_post(&receiver_ready); lc_channel_t *dst = NULL; byt = lc_socket_multi_recv(sock, buf, PAYLOADMAX, 0, &dst); test_assert(dst == chan[CHAN_LEFT], "lc_channel_recv() - LEFT channel"); test_assert(byt == PAYLOADMAX, "bytes recved on LEFT = %zi", byt); /* recv from socket, expect data on RIGHT channel */ dst = NULL; byt = lc_socket_multi_recv(sock, buf, PAYLOADMAX, 0, &dst); test_assert(dst == chan[CHAN_RIGHT], "lc_channel_recv() - RIGHT channel"); test_assert(byt == PAYLOADMAX, "bytes recved on RIGHT = %zi", byt); /* again, with lc_socket_multi_recvmsg() */ sem_post(&receiver_ready); const size_t len = PAYLOADMAX; struct iovec iov = { .iov_base = buf, .iov_len = len }; struct msghdr msg = { .msg_iov = &iov, .msg_iovlen = 1 }; dst = NULL; byt = lc_socket_multi_recvmsg(sock, &msg, 0, &dst); test_assert(dst == chan[CHAN_LEFT], "lc_channel_recvmsg() - LEFT channel"); test_assert(byt == PAYLOADMAX, "bytes recved on LEFT = %zi", byt); /* recv from socket, expect data on RIGHT channel */ dst = NULL; byt = lc_socket_multi_recvmsg(sock, &msg, 0, &dst); test_assert(dst == chan[CHAN_RIGHT], "lc_channel_recvmsg() - RIGHT channel"); test_assert(byt == PAYLOADMAX, "bytes recved on RIGHT = %zi", byt); sem_post(&timeout); err_ctx_free: lc_ctx_free(lctx); return arg; } static void *send_data(void * arg) { char *buf = (char *)arg; lc_ctx_t *lctx; lc_socket_t *sock; lc_channel_t *chan[CHANNELS]; ssize_t byt; lctx = lc_ctx_new(); if (!lctx) return NULL; sock = lc_socket_new(lctx); if (!sock) goto err_ctx_free; if (lc_socket_bind(sock, ifidx) == -1) goto err_ctx_free; lc_socket_loop(sock, 1); for (int i = 0; i < CHANNELS; i++) { chan[i] = create_and_bind_channel(lctx, sock, i); if (!chan[i]) goto err_ctx_free; } /* run twice, for lc_socket_multi_recv and lc_socket_multi_recvmsg */ for (int i = 0; i < 2; i++) { sem_wait(&receiver_ready); /* send on "LEFT" channel first */ byt = lc_channel_send(chan[CHAN_LEFT], buf, PAYLOADMAX, 0); test_assert(byt == PAYLOADMAX, "lc_channel_recv() - data sent to LEFT channel"); /* send on "RIGHT" channel now */ byt = lc_channel_send(chan[CHAN_RIGHT], buf, PAYLOADMAX, 0); test_assert(byt == PAYLOADMAX, "lc_channel_recv() - data sent to RIGHT channel"); } err_ctx_free: lc_ctx_free(lctx); return arg; } int main(void) { char name[] = "lc_socket_multi_recv()"; char buf[CHANNELS][PAYLOADMAX]; pthread_t tid[2]; struct timespec ts; int rc; test_name(name); test_require_net(TEST_NET_BASIC); ifidx = get_multicast_if(); if (!test_assert(ifidx > 0, "get_multicast_if()")) return test_status; sem_init(&timeout, 0, 0); sem_init(&receiver_ready, 0, 0); /* generate random data and clear recv buffer */ arc4random_buf(buf[TID_SEND], PAYLOADMAX); memset(buf[TID_RECV], 0, PAYLOADMAX); pthread_create(&tid[TID_SEND], NULL, &send_data, buf[TID_SEND]); pthread_create(&tid[TID_RECV], NULL, &recv_data, buf[TID_RECV]); clock_gettime(CLOCK_REALTIME, &ts); ts.tv_sec += WAITS; rc = sem_timedwait(&timeout, &ts); test_assert(rc == 0, "timeout"); pthread_cancel(tid[TID_RECV]); pthread_join(tid[TID_RECV], NULL); pthread_join(tid[TID_SEND], NULL); sem_destroy(&receiver_ready); sem_destroy(&timeout); rc = memcmp(buf[TID_RECV], buf[TID_SEND], PAYLOADMAX); test_assert(rc == 0, "recv and send buffers match"); return test_status; } librecast/test/0000-0077.c000066400000000000000000000106701502456746400151440ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2017-2025 Brett Sheffield */ #include "testnet.h" #include #include #include #include #include #include #include #include #include #undef TESTDEBUG #ifdef TESTDEBUG # define PKTS 10 # define PKTSZ 4 #else # define PKTS 20 # define PKTSZ 1024 #endif #define WAITS 2 #ifdef HAVE_LIBLCRQ static const size_t SZ = PKTS * PKTSZ + 5; enum { TID_SEND, TID_RECV }; static char channel_name[] = "0000-0039"; static sem_t receiver_ready, timeout; #ifdef TESTDEBUG static void dumppkt(uint8_t *pkt, int haseq) { uint16_t seq; uint8_t *dat = pkt; if (haseq) { dat += sizeof seq; seq = ntohs(*(uint16_t *)pkt); fprintf(stderr, "%u: ", seq); } else fprintf(stderr, " "); for (size_t z = 0; z < PKTSZ * 8; z++) { if (isset(dat, z)) putc('1', stderr); else putc('0', stderr); } putc('\n', stderr); } static void dump_bufs(uint8_t buf[2][SZ]) { for (size_t p = 0; p < PKTS; p++) { fprintf(stderr, "%zu: ", p); for (int i = 0; i < 2; i++) { for (size_t z = 0; z < PKTSZ * 8; z++) { uint8_t *b = buf[i]; if (isset(b, p * PKTSZ * 8 + z)) putc('1', stderr); else putc('0', stderr); } putc(' ', stderr); } putc('\n', stderr); } putc('\n', stderr); } #endif static void generate_source_data(uint8_t *buf, size_t sz) { ssize_t rc; int f; f = open("/dev/urandom", O_RDONLY); if (f == -1) return; rc = read(f, buf, sz); test_assert(rc == (ssize_t)sz, "%zi random bytes read", rc); close(f); } static void *recv_data_fec(void *arg) { uint8_t *buf = (uint8_t *)arg; ssize_t rc; lc_ctx_t *lctx = lc_ctx_new(); lc_socket_t * sock = lc_socket_new(lctx); lc_channel_t * chan = lc_channel_new(lctx, channel_name); memset(buf, 0, SZ); /* clear receive buffer */ lc_channel_bind(sock, chan); lc_channel_join(chan); lc_channel_coding_set(chan, LC_CODE_FEC_RQ); sem_post(&receiver_ready); rc = lc_channel_recv(chan, buf, SZ, 0); test_log("lc_channel_recv returned %zi\n", rc); test_assert(rc >= (ssize_t)SZ, "data received %zi/%zu bytes", rc, SZ); lc_channel_part(chan); lc_ctx_free(lctx); sem_post(&timeout); return arg; } static void *send_data_fec(void *arg) { uint8_t *buf = (uint8_t *)arg; struct iovec iov = { .iov_base = buf, .iov_len = SZ }; struct msghdr msg = { .msg_iov = &iov, .msg_iovlen = 1 }; lc_ctx_t *lctx = lc_ctx_new(); lc_socket_t * sock = lc_socket_new(lctx); lc_channel_t * chan = lc_channel_new(lctx, channel_name); rq_t *rq; ssize_t rc; size_t byt = 0; lc_socket_loop(sock, 1); lc_channel_bind(sock, chan); lc_channel_coding_set(chan, LC_CODE_FEC_RQ); test_log("sending data with FEC\n"); sem_wait(&receiver_ready); /* preset RQ overhead to send */ lc_channel_rq_overhead(chan, RQ_OVERHEAD * 2); rc = lc_channel_sendmsg(chan, &msg, 0); test_assert(rc > 0, "lc_channel_send encoded data, returned %zi", rc); if (rc == -1) goto err_ctx_free; byt = rc; rq = lc_channel_rq(chan); if (!test_assert(rq != NULL, "lc_channel_rq()")) goto err_ctx_free; test_assert(byt >= SZ, "data sent %zi bytes (buffer = %zu)", byt, SZ); err_ctx_free: lc_ctx_free(lctx); return arg; } #endif int main(void) { char name[] = "lc_channel_sendmsg() with preset RQ overhead"; #ifndef HAVE_LIBLCRQ return test_skip(name); #else pthread_t tid[2]; uint8_t *buf[2]; struct timespec ts; int rc; test_name(name); test_require_net(TEST_NET_BASIC); buf[TID_SEND] = malloc(SZ); assert(buf[TID_SEND]); buf[TID_RECV] = malloc(SZ); assert(buf[TID_RECV]); memset(buf[0], 0, SZ); memset(buf[1], 0, SZ); sem_init(&timeout, 0, 0); sem_init(&receiver_ready, 0, 0); generate_source_data(buf[TID_SEND], SZ); test_assert(memcmp(buf[TID_RECV], buf[TID_SEND], SZ), "buffer differ before sync"); pthread_create(&tid[TID_SEND], NULL, &send_data_fec, buf[TID_SEND]); pthread_create(&tid[TID_RECV], NULL, &recv_data_fec, buf[TID_RECV]); clock_gettime(CLOCK_REALTIME, &ts); ts.tv_sec += WAITS; rc = sem_timedwait(&timeout, &ts); test_assert(rc == 0, "timeout"); pthread_cancel(tid[TID_RECV]); pthread_join(tid[TID_RECV], NULL); pthread_join(tid[TID_SEND], NULL); sem_destroy(&receiver_ready); sem_destroy(&timeout); if (!rc) test_assert(!memcmp(buf[TID_RECV], buf[TID_SEND], SZ), "send buffer matches received"); #ifdef TESTDEBUG dump_bufs(buf); #endif free(buf[TID_SEND]); free(buf[TID_RECV]); return test_status; #endif } librecast/test/0000-0078.c000066400000000000000000000111571502456746400151460ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2025 Brett A C Sheffield */ #include "test.h" #include "testnet.h" #include #include #include #include #include #include #define WAITS 4 /* timeout seconds */ #define TEST_SIZE 1024 #define TEST_NAME "netlink interface detection" #ifdef HAVE_LINUX_NETLINK_H static sem_t sem_done; static sem_t sem_recv; enum { RECV, SEND }; static char send_buf[TEST_SIZE]; static void *thread_recv(void *arg) { lc_ctx_t *lctx; lc_socket_t *sock; lc_channel_t *chan; char buf[BUFSIZ]; ssize_t byt; int rc; lctx = lc_ctx_new(); if (!test_assert(lctx != NULL, "lc_ctx_new()")) return NULL; sock = lc_socket_new(lctx); if (!test_assert(sock != NULL, "lc_socket_new()")) goto free_ctx; chan = lc_channel_new(lctx, TEST_NAME); if (!test_assert(chan != NULL, "lc_channel_new()")) goto free_ctx; rc = lc_channel_bind(sock, chan); if (!test_assert(rc == 0, "lc_channel_bind()")) goto free_ctx; rc = lc_channel_join(chan); if (!test_assert(rc == 0, "lc_channel_join()")) goto free_ctx; memset(buf, 0, sizeof buf); sem_post(&sem_recv); /* tell sender we're ready */ byt = lc_channel_recv(chan, buf, TEST_SIZE, 0); if (byt == -1) perror("lc_channel_recv"); test_assert(byt == TEST_SIZE, "lc_channel_recv() returned %zi", byt); test_assert(memcmp(send_buf, buf, TEST_SIZE) == 0, "received data matches"); sem_post(&sem_done); /* tell ctrl thread we are finished */ free_ctx: lc_ctx_free(lctx); return arg; } static void disable_dad(char *ifname) { char fname[128]; char sysvar[] = "/proc/sys/net/ipv6/conf/%s/accept_dad"; int fd; snprintf(fname, 128, sysvar, ifname); fd = open(fname, O_WRONLY); test_assert(write(fd, "0", 1) == 1, "write"); close(fd); } static void *thread_send(void *arg) { lc_ctx_t *lctx; lc_socket_t *sock; lc_channel_t *chan; char ifname[IFNAMSIZ] = {0}; ssize_t byt; unsigned int ifx; int fd; int rc; lctx = lc_ctx_new(); if (!test_assert(lctx != NULL, "lc_ctx_new()")) return NULL; sock = lc_socket_new(lctx); if (!test_assert(sock != NULL, "lc_socket_new()")) goto free_ctx; chan = lc_channel_new(lctx, TEST_NAME); if (!test_assert(chan != NULL, "lc_channel_new()")) goto free_ctx; rc = lc_channel_bind(sock, chan); if (!test_assert(rc == 0, "lc_channel_bind()")) goto free_ctx; lc_socket_loop(sock, 1); sem_wait(&sem_recv); /* wait for receiver to be ready */ /* create a new interface and use that to send */ fd = lc_tap_create(ifname); if (fd == -1) perror("lc_tap_create"); test_assert(fd >= 0, "lc_tap_create() returned %i", fd); disable_dad(ifname); /* otherwise we need to sleep 2s for DAD */ rc = lc_link_set(lctx, ifname, 1); if (!test_assert(rc == 0, "bring up interface")) goto free_ctx; ifx = if_nametoindex(ifname); if (!test_assert(ifx > 0, "find ifx for %s == %u", ifname, ifx)) goto free_ctx; rc = lc_socket_bind(sock, ifx); if (!test_assert(rc == 0, "bind to interface %u", ifx)) goto free_ctx; /* allow time for recv to handle netlink event */ if (RUNNING_ON_VALGRIND) sleep(2); else usleep(10000); byt = lc_channel_send(chan, send_buf, sizeof send_buf, 0); if (byt == -1) perror("lc_channel_send"); test_assert(byt == (ssize_t)TEST_SIZE, "lc_channel_send() returned %zi / %zi", byt, TEST_SIZE); free_ctx: lc_ctx_free(lctx); return arg; } static int test_netlink(void) { pthread_t tid[2]; void *(*thread_f[2])(void *) = { &thread_recv, &thread_send }; int threads = 0; int rc; /* generate test data */ arc4random_buf(send_buf, sizeof send_buf); rc = sem_init(&sem_done, 0, 0); if (!test_assert(rc == 0, "sem_init() sem_done")) return test_status; rc = sem_init(&sem_recv, 0, 0); if (!test_assert(rc == 0, "sem_init() sem_recv")) goto free_sem_done; /* start threads */ for (int i = 0; i < 2; i++) { rc = pthread_create(&tid[i], NULL, thread_f[i], NULL); if (!test_assert(rc == 0, "%i: pthread_create", i)) goto join_threads; threads++; } /* timeout */ struct timespec ts; if (!test_assert(!clock_gettime(CLOCK_REALTIME, &ts), "clock_gettime()")) goto join_threads; ts.tv_sec += WAITS; test_assert(!sem_timedwait(&sem_done, &ts), "timeout"); join_threads: for (int i = 0; i < threads; i++) { pthread_cancel(tid[i]); pthread_join(tid[i], NULL); } sem_destroy(&sem_recv); free_sem_done: sem_destroy(&sem_done); return test_status; } #endif /* HAVE_LINUX_NETLINK_H */ int main(void) { char name[] = TEST_NAME; test_cap_require(CAP_NET_ADMIN); test_name(name); #ifdef HAVE_LINUX_NETLINK_H test_require_net(TEST_NET_BASIC); if (test_netlink()) return test_status; #endif return test_status; } librecast/test/0000-0079.c000066400000000000000000000037351502456746400151520ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2025 Brett A C Sheffield */ /* We don't really need much of an API for managing keys or keyrings, yet. * At the point where we need to manage and search large keyrings it might be * worth using different data structure, and then we will want functions to manage * keyrings */ #include "test.h" #include int main(void) { char name[] = "keyring API calls"; lc_keypair_t key[8]; lc_keyring_t keyring = {0}; int nkeys = (int)(sizeof key / sizeof key[0]); int rc; test_name(name); rc = lc_keyring_init(&keyring, nkeys); /* add keys to keyring */ for (int i = 0; i < nkeys; i++ ) { rc = lc_keypair_new(&key[i], LC_KEY_SIG); test_assert(rc == 0, "lc_keypair_new(LC_KEY_SIGN) [%i]", i); rc = lc_keyring_has(&keyring, key[i].pk); test_assert(rc == 0, "lc_keyring_has() - key[%i] not on ring before adding", i); rc = lc_keyring_add(&keyring, key[i].pk); test_assert(rc == 0, "lc_keyring_add()[%i]", i); } /* ensure all added keys on keyring */ for (int i = 0; i < nkeys; i++ ) { rc = lc_keyring_has(&keyring, key[i].pk); test_assert(rc == -1, "lc_keyring_has() - key[%i] on ring after adding", i); } /* delete a key */ const int idxdeleted = 5; rc = lc_keyring_del(&keyring, key[idxdeleted].pk); test_assert(rc == 0, "lc_keyring_del()"); rc = lc_keyring_has(&keyring, key[idxdeleted].pk); test_assert(rc == 0, "lc_keyring_has() - key not on ring after deleting"); errno = 0; rc = lc_keyring_del(&keyring, key[idxdeleted].pk); test_assert(errno == ENOKEY, "lc_keyring_del() - ENOKEY when key not exist"); test_assert(rc == -1, "lc_keyring_del() - return -1 when key not exist"); /* ensure other keys all still exist */ for (int i = 0; i < nkeys; i++ ) { if (i == idxdeleted) continue; rc = lc_keyring_has(&keyring, key[i].pk); test_assert(rc == -1, "lc_keyring_has() - key[%i] on ring", i); } lc_keyring_free(&keyring); return test_status; } librecast/test/0000-0082.c000066400000000000000000000062471502456746400151450ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2025 Brett A C Sheffield */ /* test send functions can take NULL, 0 data with RaptorQ * * - lc_socket_send * - lc_socket_sendmsg * - lc_channel_send * - lc_channel_sendmsg * */ #include "test.h" #include #ifdef HAVE_LIBLCRQ enum { NO_FEC, FEC, }; static int test_prepare_to_send(lc_ctx_t **lctx, lc_socket_t **sock, lc_channel_t **chan, int use_fec) { int rc; *lctx = lc_ctx_new(); if (!test_assert(lctx != NULL, "lc_ctx_new()")) return test_status; *sock = lc_socket_new(*lctx); if (!test_assert(sock != NULL, "lc_socket_new()")) return test_status; *chan = lc_channel_new(*lctx, "nada"); if (!test_assert(*chan != NULL, "lc_channel_new()")) return test_status; rc = lc_channel_bind(*sock, *chan); if (!test_assert(rc == 0, "lc_channel_bind()")) return test_status; if (use_fec) lc_channel_coding_set(*chan, LC_CODE_FEC_RQ); return test_status; } static int test_socket_sendmsg(int use_fec) { lc_ctx_t *lctx = NULL; lc_socket_t *sock = NULL; lc_channel_t *chan = NULL; struct msghdr msg = { .msg_iov = NULL, .msg_iovlen = 0 }; ssize_t byt; if (test_prepare_to_send(&lctx, &sock, &chan, use_fec)) goto free_ctx; byt = lc_socket_sendmsg(sock, &msg, 0); test_assert(byt >= 0, "%s returned %zi with NULL data (FEC=%i)", __func__, byt, use_fec); free_ctx: if (lctx) lc_ctx_free(lctx); return test_status; } static int test_channel_sendmsg(int use_fec) { lc_ctx_t *lctx; lc_socket_t *sock; lc_channel_t *chan; struct msghdr msg = { .msg_iov = NULL, .msg_iovlen = 0 }; ssize_t byt; if (test_prepare_to_send(&lctx, &sock, &chan, use_fec)) goto free_ctx; byt = lc_channel_sendmsg(chan, &msg, 0); test_assert(byt >= 0, "%s returned %zi with NULL data (FEC=%i)", __func__, byt, use_fec); free_ctx: lc_ctx_free(lctx); return test_status; } static int test_socket_send(int use_fec) { lc_ctx_t *lctx; lc_socket_t *sock; lc_channel_t *chan; ssize_t byt; if (test_prepare_to_send(&lctx, &sock, &chan, use_fec)) goto free_ctx; byt = lc_socket_send(sock, NULL, 0, 0); test_assert(byt >= 0, "%s returned %zi with NULL data (FEC=%i)", __func__, byt, use_fec); free_ctx: lc_ctx_free(lctx); return test_status; } static int test_channel_send(int use_fec) { lc_ctx_t *lctx; lc_socket_t *sock; lc_channel_t *chan; ssize_t byt; if (test_prepare_to_send(&lctx, &sock, &chan, use_fec)) goto free_ctx; byt = lc_channel_send(chan, NULL, 0, 0); test_assert(byt >= 0, "%s returned %zi with NULL data (FEC=%i)", __func__, byt, use_fec); free_ctx: lc_ctx_free(lctx); return test_status; } #endif int main(void) { char name[] = "send zero length data with RaptorQ"; #ifdef HAVE_LIBLCRQ test_name(name); if (test_channel_send(NO_FEC)) return test_status; if (test_channel_send(FEC)) return test_status; if (test_channel_sendmsg(NO_FEC)) return test_status; if (test_channel_sendmsg(FEC)) return test_status; if (test_socket_send(NO_FEC)) return test_status; if (test_socket_send(FEC)) return test_status; if (test_socket_sendmsg(NO_FEC)) return test_status; if (test_socket_sendmsg(FEC)) return test_status; return test_status; #else return test_skip(name); #endif } librecast/test/0000-0083.c000066400000000000000000000070261502456746400151420ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2025 Brett A C Sheffield */ /* test send functions return nett bytes sent, without overhead */ #include "test.h" #include "testnet.h" #include #define CHANNEL_NAME "0000-0083" #ifdef HAVE_LIBLCRQ static char data[1024]; static unsigned int ifidx; static int test_prepare_to_send(lc_ctx_t **lctx, lc_socket_t **sock, lc_channel_t **chan, int encodings) { int rc; *lctx = lc_ctx_new(); if (!test_assert(lctx != NULL, "lc_ctx_new()")) return test_status; *sock = lc_socket_new(*lctx); if (!test_assert(sock != NULL, "lc_socket_new()")) return test_status; rc = lc_socket_bind(*sock, ifidx); if (rc == -1) perror("lc_socket_bind"); if (!test_assert(rc == 0, "lc_socket_bind() ifx = %u", ifidx)) return test_status; *chan = lc_channel_new(*lctx, CHANNEL_NAME); if (!test_assert(*chan != NULL, "lc_channel_new()")) return test_status; rc = lc_channel_bind(*sock, *chan); if (!test_assert(rc == 0, "lc_channel_bind()")) return test_status; rc = lc_channel_join(*chan); if (!test_assert(rc == 0, "lc_channel_join()")) return test_status; rc = lc_socket_loop(*sock, 1); if (!test_assert(rc == 0, "lc_socket_loop()")) return test_status; if (encodings) { lc_channel_coding_set(*chan, encodings); if (encodings & LC_CODE_FEC_RQ) lc_channel_rq_overhead(*chan, RQ_OVERHEAD * 2); } return test_status; } static int test_channel_send(int encodings) { lc_ctx_t *lctx; lc_socket_t *sock; lc_channel_t *chan = NULL; char buf[BUFSIZ]; ssize_t byt; /* generate random data to send */ ssize_t len = arc4random_uniform(sizeof data); arc4random_buf(data, len); if (test_prepare_to_send(&lctx, &sock, &chan, encodings)) goto free_ctx; byt = lc_channel_send(chan, data, len, 0); if (byt == -1) perror("lc_channel_send"); if (!test_assert(byt == len, "%s returned %zi (expected %zi) with enc=%i", __func__, byt, len, encodings)) goto free_ctx; byt = lc_channel_recv(chan, buf, sizeof buf, 0); test_assert(byt == len, "%s recv'ed %zi (expected %zi) with enc=%i", __func__, byt, len, encodings); free_ctx: lc_ctx_free(lctx); return test_status; } static int test_channel_sendmsg(int encodings) { lc_ctx_t *lctx; lc_socket_t *sock; lc_channel_t *chan = NULL; char buf[BUFSIZ]; ssize_t byt; /* generate random data to send */ ssize_t len = arc4random_uniform(sizeof data); arc4random_buf(data, len); struct iovec iov = { .iov_base = data, .iov_len = len }; struct msghdr msg = { .msg_iov = &iov, .msg_iovlen = 1 }; if (test_prepare_to_send(&lctx, &sock, &chan, encodings)) goto free_ctx; byt = lc_channel_sendmsg(chan, &msg, 0); if (byt == -1) perror("lc_channel_sendmsg"); if (!test_assert(byt == len, "%s returned %zi (expected %zi) with enc=%i", __func__, byt, len, encodings)) goto free_ctx; iov.iov_base = buf; byt = lc_channel_recvmsg(chan, &msg, 0); test_assert(byt == len, "%s recv'ed %zi (expected %zi) with enc=%i", __func__, byt, len, encodings); free_ctx: lc_ctx_free(lctx); return test_status; } #endif int main(void) { char name[] = "check send/recv return values"; #ifdef HAVE_LIBLCRQ test_name(name); test_require_net(TEST_NET_BASIC); ifidx = get_multicast_if(); if (!test_assert(ifidx > 0, "get_multicast_if()")) return test_status; if (test_channel_send(0)) return test_status; if (test_channel_send(LC_CODE_FEC_RQ)) return test_status; if (test_channel_sendmsg(0)) return test_status; if (test_channel_sendmsg(LC_CODE_FEC_RQ)) return test_status; return test_status; #else return test_skip(name); #endif } librecast/test/0000-0084.c000066400000000000000000000054641502456746400151470ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2025 Brett A C Sheffield */ /* test send functions return nett bytes sent, without overhead */ #include "test.h" #include "testnet.h" #include #include #define CHANNEL_NAME "0000-0084" #ifdef HAVE_LIBLCRQ static char data[BUFSIZ]; enum { SEND, RECV, }; static int test_channel_send(int use_fec) { lc_ctx_t *lctx; lc_socket_t *sock[2]; lc_channel_t *chan[2]; char buf[BUFSIZ]; ssize_t byt; int rc; /* generate random data to send */ ssize_t len = arc4random_uniform(sizeof data); arc4random_buf(data, len); lctx = lc_ctx_new(); if (!test_assert(lctx != NULL, "lc_ctx_new()")) return test_status; rc = lc_socketpair(lctx, sock); if (!test_assert(rc == 0, "lc_socket_new()")) goto free_ctx; for (int i = 0; i < 2; i++) { chan[i] = lc_channel_new(lctx, CHANNEL_NAME); if (!test_assert(chan[i] != NULL, "lc_channel_new()[%i]", i)) goto free_ctx; rc = lc_channel_bind(sock[i], chan[i]); if (!test_assert(rc == 0, "lc_channel_bind()[%i]", i)) goto free_ctx; if (use_fec) { lc_channel_coding_set(chan[i], LC_CODE_FEC_RQ); lc_channel_rq_overhead(chan[i], RQ_OVERHEAD * 2); } } rc = lc_channel_join(chan[RECV]); if (!test_assert(rc == 0, "lc_channel_join()")) goto free_ctx; lc_keypair_t signerkey; lc_token_t tok = {0}; lc_key_t ssk; rc = lc_keypair_new(&signerkey, LC_KEY_SIG); if (!test_assert(rc == 0, "lc_keypair_new()")) goto free_ctx; ssk.key = signerkey.sk; ssk.keylen = sizeof signerkey.sk; rc = lc_token_new(&tok, &signerkey, signerkey.pk, chan[0], 0, 0); if (!test_assert(rc == 0, "lc_token_new()")) goto free_ctx; lc_channel_setkey(chan[SEND], &ssk, LC_CODE_SIGN); lc_channel_token_set(chan[SEND], &tok); /* recv filter */ lc_keyring_t keyring = {0}; rc = lc_keyring_init(&keyring, 1); if (!test_assert(rc == 0, "lc_keyring_init()")) goto free_ctx; rc = lc_keyring_add(&keyring, signerkey.pk); if (!test_assert(rc == 0, "lc_keyring_add()")) goto free_keyring; lc_filter_t filter = { .keyring = &keyring }; lc_channel_filter_set(chan[RECV], &filter); byt = lc_channel_send(chan[SEND], data, len, 0); test_assert(byt == len, "lc_channel_send() returned %zi (expected %zi)", byt, len); if (byt == -1 && errno == ENOBUFS) { test_status = TEST_WARN; goto free_keyring; } byt = lc_channel_recv(chan[RECV], buf, len, 0); test_assert(byt == len, "recv'ed %zi (expected %zi)", byt, len); free_keyring: lc_keyring_free(&keyring); free_ctx: lc_ctx_free(lctx); return test_status; } #endif int main(void) { char name[] = "check send/recv return values (token + filter)"; #ifdef HAVE_LIBLCRQ test_name(name); test_require_net(TEST_NET_BASIC); test_channel_send(0); test_channel_send(1); return test_status; #else return test_skip(name); #endif } librecast/test/0000-0088.c000066400000000000000000000110641502456746400151440ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2017-2025 Brett Sheffield */ #include "testnet.h" #include #include #include #include #include #include #include #include #include #undef TESTDEBUG #ifdef TESTDEBUG # define PKTS 10 # define PKTSZ 4 #else # define PKTS 20 # define PKTSZ 1024 #endif #define WAITS 20 #ifdef HAVE_LIBLCRQ enum { TID_SEND, TID_RECV }; static const size_t SZ = PKTS * PKTSZ + 5; static char channel_name[] = "0000-0088"; static sem_t receiver_ready, timeout; #ifdef TESTDEBUG static void dumppkt(uint8_t *pkt, int haseq) { uint16_t seq; uint8_t *dat = pkt; if (haseq) { dat += sizeof seq; seq = ntohs(*(uint16_t *)pkt); fprintf(stderr, "%u: ", seq); } else fprintf(stderr, " "); for (size_t z = 0; z < PKTSZ * 8; z++) { if (isset(dat, z)) putc('1', stderr); else putc('0', stderr); } putc('\n', stderr); } static void dump_bufs(uint8_t buf[2][SZ]) { for (size_t p = 0; p < PKTS; p++) { fprintf(stderr, "%zu: ", p); for (int i = 0; i < 2; i++) { for (size_t z = 0; z < PKTSZ * 8; z++) { uint8_t *b = buf[i]; if (isset(b, p * PKTSZ * 8 + z)) putc('1', stderr); else putc('0', stderr); } putc(' ', stderr); } putc('\n', stderr); } putc('\n', stderr); } #endif static void generate_source_data(uint8_t *buf, size_t sz) { ssize_t rc; int f; f = open("/dev/urandom", O_RDONLY); if (f == -1) return; rc = read(f, buf, sz); test_assert(rc == (ssize_t)sz, "%zi random bytes read", rc); close(f); } static void *recv_data_fec(void *arg) { uint8_t *buf = (uint8_t *)arg; ssize_t rc; lc_ctx_t *lctx = lc_ctx_new(); lc_socket_t * sock = lc_socket_new(lctx); lc_channel_t * chan = lc_channel_new(lctx, channel_name); memset(buf, 0, SZ); /* clear receive buffer */ lc_channel_bind(sock, chan); lc_channel_join(chan); lc_channel_coding_set(chan, LC_CODE_FEC_RQ | LC_CODE_FEC_OTI); sem_post(&receiver_ready); rc = lc_channel_recv(chan, buf, SZ * 2, 0); test_log("lc_channel_recv returned %zi\n", rc); test_assert(rc == (ssize_t)SZ, "data received %zi/%zu bytes", rc, SZ); lc_channel_part(chan); lc_ctx_free(lctx); sem_post(&timeout); return arg; } static void *send_data_fec(void *arg) { uint8_t *buf = (uint8_t *)arg; lc_ctx_t *lctx = lc_ctx_new(); lc_socket_t * sock = lc_socket_new(lctx); lc_channel_t * chan = lc_channel_new(lctx, channel_name); rq_t *rq; ssize_t rc; size_t byt = 0; lc_socket_loop(sock, 1); lc_channel_bind(sock, chan); lc_channel_coding_set(chan, LC_CODE_FEC_RQ | LC_CODE_FEC_OTI); test_log("sending data with FEC\n"); sem_wait(&receiver_ready); rc = lc_channel_send(chan, buf, SZ, 0); test_assert(rc > 0, "lc_channel_send encoded data, returned %zi", rc); if (rc == -1) goto err_ctx_free; byt = rc; rq = lc_channel_rq(chan); /* Send packets. Drop packet 3 */ int pkts = rq_KP(rq) + RQ_OVERHEAD * 2; test_log("sending %u packets\n", pkts); for (int i = 1; i < pkts; i++) { int flags = (i == 3) ? MSG_DROP : 0; rc = lc_channel_send(chan, NULL, 0, flags); test_assert(rc > 0, "lc_channel_send encoded data, returned %zi", rc); if (rc > 0) byt += rc; } test_assert(byt >= SZ, "data sent %zi bytes (buffer = %zu)", byt, SZ); err_ctx_free: lc_ctx_free(lctx); return arg; } #endif int main(void) { char name[] = "lc_channel_send() / lc_channel_recv() - RaptorQ + OTI"; #ifndef HAVE_LIBLCRQ return test_skip(name); #else pthread_t tid[2]; uint8_t *buf[2]; struct timespec ts; int rc; test_name(name); test_require_net(TEST_NET_BASIC); buf[TID_SEND] = malloc(SZ); assert(buf[TID_SEND]); buf[TID_RECV] = malloc(SZ * 2); assert(buf[TID_RECV]); memset(buf[0], 0, SZ); memset(buf[1], 0, SZ); sem_init(&timeout, 0, 0); sem_init(&receiver_ready, 0, 0); generate_source_data(buf[TID_SEND], SZ); test_assert(memcmp(buf[TID_RECV], buf[TID_SEND], SZ), "buffer differ before sync"); pthread_create(&tid[TID_SEND], NULL, &send_data_fec, buf[TID_SEND]); pthread_create(&tid[TID_RECV], NULL, &recv_data_fec, buf[TID_RECV]); clock_gettime(CLOCK_REALTIME, &ts); ts.tv_sec += WAITS; rc = sem_timedwait(&timeout, &ts); test_assert(rc == 0, "timeout"); pthread_cancel(tid[TID_RECV]); pthread_join(tid[TID_RECV], NULL); pthread_join(tid[TID_SEND], NULL); sem_destroy(&receiver_ready); sem_destroy(&timeout); if (!rc) test_assert(!memcmp(buf[TID_RECV], buf[TID_SEND], SZ), "send buffer matches received"); #ifdef TESTDEBUG dump_bufs(buf); #endif free(buf[TID_SEND]); free(buf[TID_RECV]); return test_status; #endif } librecast/test/0000-0090.c000066400000000000000000000036401502456746400151360ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2025 Brett A C Sheffield */ #include "test.h" #include #include #include #include #include void handle_sigint(int signo, siginfo_t *info, void *context) { (void)signo, (void) info, (void)context; } static pid_t fork_and_recv(void) { pid_t pid = fork(); if (pid) return pid; /* child continues */ char buf[BUFSIZ]; ssize_t byt; int ret = EXIT_FAILURE; struct sigaction act = {0}; act.sa_sigaction = &handle_sigint; if (sigaction(SIGINT, &act, NULL) == -1) { perror("sigaction"); _exit(EXIT_FAILURE); } lc_ctx_t *lctx; lc_socket_t *sock; lc_channel_t *chan; lctx = lc_ctx_new(); if (!(test_assert(lctx != NULL, "lc_ctx_new()"))) _exit(EXIT_FAILURE); sock = lc_socket_new(lctx); if (!(test_assert(sock != NULL, "lc_socket_new()"))) goto free_lctx; chan = lc_channel_new(lctx, "0000-0090"); if (!(test_assert(chan != NULL, "lc_channel_new()"))) goto free_lctx; lc_channel_bind(sock, chan); /* wait for signal */ assert(chan); byt = lc_channel_recv(chan, buf, sizeof buf, 0); test_assert(errno == EINTR, "EINTR"); test_assert(byt == -1, "lc_channel_recv() returned %zi", byt); ret = EXIT_SUCCESS; free_lctx: lc_ctx_free(lctx); _exit(ret); } int main(void) { char name[] = "EINTR: recv calls can be interupted with signals"; pid_t pid; int wstatus; int rc; test_name(name); if (RUNNING_ON_VALGRIND) return TEST_WARN; pid = fork_and_recv(); if (!test_assert(pid != -1, "fork returned %i", pid)) return test_status; usleep(10000); test_log("sending SIGINT to pid %i\n", pid); kill(pid, SIGINT); rc = waitpid(pid, &wstatus, 0); if (!test_assert(WIFEXITED(wstatus), "WIFEXITED")) return test_status; rc = WEXITSTATUS(wstatus); if (!test_assert(rc == EXIT_SUCCESS, "child exited with %i", rc)) return test_status; return test_status; } librecast/test/0000-0091.c000066400000000000000000000110701502456746400151330ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2025 Brett A C Sheffield */ #include "test.h" #include "testnet.h" #include #include #include #include #define TEST_NAME "FEC + OTI with variable sized objects" #if (HAVE_LIBLCRQ && HAVE_RQ_OTI) #define ITERATIONS 2 #define SPEED_LIMIT 1024 * 1024 * 32 /* 32Mbps */ #define WAITS 4 static sem_t sem; static size_t len[ITERATIONS]; static char data[ITERATIONS][BUFSIZ]; static unsigned int ifidx; static void *thread_recv(void * arg) { (void)arg; lc_ctx_t *lctx = NULL; lc_socket_t *sock; lc_channel_t *chan; char buf[BUFSIZ]; ssize_t byt; int rc; pthread_cleanup_push((void (*)(void *))lc_ctx_free, lctx); lctx = lc_ctx_new(); if (!test_assert(lctx != NULL, "lc_ctx_new()")) return NULL; sock = lc_socket_new(lctx); if (!test_assert(sock != NULL, "lc_socket_new()")) goto lctx_free; if (!test_assert(lc_socket_bind(sock, ifidx) == 0, "lc_socket_bind() ifx = %u", ifidx)) goto lctx_free; chan = lc_channel_new(lctx, TEST_NAME); if (!test_assert(chan != NULL, "lc_channel_new()")) goto lctx_free; lc_channel_bind(sock, chan); lc_channel_coding_set(chan, LC_CODE_FEC_RQ | LC_CODE_FEC_OTI); rc = lc_channel_join(chan); if (!test_assert(rc == 0, "lc_channel_join()")) goto lctx_free; for (int i = 0; i < ITERATIONS; i++) { unsigned char hash[HASHSIZE]; memset(buf, 0, sizeof buf); byt = lc_channel_recv(chan, buf, sizeof buf, 0); if (!test_assert(byt == (ssize_t)len[i], "%zu/%zi bytes recv", len[i], byt)) break; hash_generic(hash, sizeof hash, (unsigned char *)data[i], len[i]); fprintf(stderr, "%i: expected: ", i); hash_hex_debug(stderr, hash, HASHSIZE); hash_generic(hash, sizeof hash, (unsigned char *)buf, len[i]); fprintf(stderr, "%i: got: ", i); hash_hex_debug(stderr, hash, HASHSIZE); if (!test_assert(!memcmp(data[i], buf, len[i]), "data matches (%zu bytes)", len[i])) break; } lctx_free: pthread_cleanup_pop(1); /* lc_ctx_free(lctx); */ sem_post(&sem); return NULL; } static void *thread_send(void * arg) { (void)arg; lc_ctx_t *lctx = NULL; lc_socket_t *sock; lc_channel_t *chan; ssize_t byt; pthread_cleanup_push((void (*)(void *))lc_ctx_free, lctx); lctx = lc_ctx_new(); if (!test_assert(lctx != NULL, "lc_ctx_new()")) return NULL; sock = lc_socket_new(lctx); if (!test_assert(sock != NULL, "lc_socket_new()")) goto lctx_free; if (!test_assert(lc_socket_bind(sock, ifidx) == 0, "lc_socket_bind() ifx = %u", ifidx)) goto lctx_free; lc_socket_loop(sock, 1); chan = lc_channel_new(lctx, TEST_NAME); if (!test_assert(chan != NULL, "lc_channel_new()")) goto lctx_free; lc_channel_bind(sock, chan); lc_channel_coding_set(chan, LC_CODE_FEC_RQ | LC_CODE_FEC_OTI); lc_channel_rq_overhead(chan, RQ_OVERHEAD * 2); lc_channel_ratelimit(chan, SPEED_LIMIT, 0); /* generate payload data */ arc4random_buf(data, sizeof data); for (int i = 0; i < ITERATIONS; i++) { unsigned char hash[HASHSIZE]; len[i] = arc4random_uniform(BUFSIZ); hash_generic(hash, sizeof hash, (unsigned char *)data[i], len[i]); fprintf(stderr, "%i: ", i); hash_hex_debug(stderr, hash, HASHSIZE); byt = lc_channel_send(chan, data[i], len[i], 0); if (!test_assert(byt == (ssize_t)len[i], "%zi/%zu bytes sent", byt, len[i])) break; } lctx_free: pthread_cleanup_pop(1); /* lc_ctx_free(lctx); */ return NULL; } static int test_oti_sizes(void) { enum { TID_SEND, TID_RECV }; pthread_t tid[2]; struct timespec timeout; int threads = sizeof tid / sizeof tid[0]; int rc; rc = sem_init(&sem, 0, 0); if (!test_assert(rc == 0, "sem_init()")) return test_status; rc = pthread_create(&tid[TID_SEND], NULL, &thread_send, NULL); if (!test_assert(rc == 0, "create send thread")) goto free_sem; rc = pthread_create(&tid[TID_RECV], NULL, &thread_recv, NULL); if (!test_assert(rc == 0, "create recv thread")) goto free_sem; rc = clock_gettime(CLOCK_REALTIME, &timeout); if (!test_assert(rc == 0, "clock_gettime()")) goto stop_threads; timeout.tv_sec += WAITS; rc = sem_timedwait(&sem, &timeout); test_assert(rc == 0, "timeout"); stop_threads: for (int i = 0; i < threads; i++) { pthread_cancel(tid[i]); pthread_join(tid[i], NULL); } free_sem: sem_destroy(&sem); return test_status; } #endif int main(void) { char name[] = TEST_NAME; #if (HAVE_LIBLCRQ && HAVE_RQ_OTI) test_name(name); test_require_net(TEST_NET_BASIC); ifidx = get_multicast_if(); if (!test_assert(ifidx > 0, "get_multicast_if()")) return test_status; test_oti_sizes(); return test_status; #else return test_skip("%s (lcrq + oti required)", name); #endif } librecast/test/0000-0092.c000066400000000000000000000023201502456746400151320ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2025 Brett A C Sheffield */ /* call lc_channel_recv() without channel bound to socket */ #include "test.h" #include #include static int test_channel_bound(void) { char buf[BUFSIZ]; lc_ctx_t *lctx; lc_socket_t *sock; lc_channel_t *chan; ssize_t byt; lctx = lc_ctx_new(); if (!(test_assert(lctx != NULL, "lc_ctx_new()"))) _exit(EXIT_FAILURE); sock = lc_socket_new(lctx); if (!(test_assert(sock != NULL, "lc_socket_new()"))) goto free_lctx; chan = lc_channel_new(lctx, "0000-0090"); if (!(test_assert(chan != NULL, "lc_channel_new()"))) goto free_lctx; byt = lc_channel_recv(chan, buf, sizeof buf, 0); test_assert(errno == ENOTSOCK, "ENOTSOCK"); test_assert(byt == -1, "lc_channel_recv() returned %zi", byt); struct msghdr msg = {0}; byt = lc_channel_recvmsg(chan, &msg, 0); test_assert(errno == ENOTSOCK, "ENOTSOCK"); test_assert(byt == -1, "lc_channel_recvmsg() returned %zi", byt); free_lctx: lc_ctx_free(lctx); return test_status; } int main(void) { char name[] = "lc_channel_recv(): channel MUST be bound"; test_name(name); test_channel_bound(); return test_status; } librecast/test/0000-0093.c000066400000000000000000000227261502456746400151470ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2025 Brett A C Sheffield */ #include "test.h" #include "testnet.h" #include #include #include #include #define TEST_NAME "restricted channels" #if defined(HAVE_LIBLCRQ) && (HAVE_LIBSODIUM) #define WAITS 4 /* timeout seconds */ #define TOKEN_SECONDS 60 #define TEST_SIZE 1024 #define SPEED_LIMIT 1024 * 1024 * 32 /* 32Mbps */ enum { RECV, SEND }; static sem_t sem; static sem_t sem_recv; static uint8_t *senderpubkey; static uint8_t *signerpubkey; static lc_token_t *sendertoken; static char send_buf[TEST_SIZE]; static char fake_buf[TEST_SIZE]; static lc_token_t token; static lc_keypair_t signerkey; /* needs to be global so we can create bad tokens */ static lc_key_t ssk; static lc_key_t bad_ssk; static unsigned char *enckey; /* symmetric encryption key */ static unsigned int ifidx; static int multi; static uint8_t capbits = 42; static void *thread_recv(void *arg) { lc_channel_t *chan = arg; lc_channel_t *dst; lc_keyring_t keyring = {0}; lc_filter_t filter; char buf[BUFSIZ]; ssize_t byt; int rc; /* set filter on channel */ rc = lc_keyring_init(&keyring, 1); rc = lc_keyring_add(&keyring, signerpubkey); test_assert(rc == 0, "lc_keyring_add()"); filter.keyring = &keyring; filter.capbits = capbits; lc_channel_filter_set(chan, &filter); /* We recv once and exit. If the filter is working, we only recv the * good (last) packet. If not, we have garbage */ memset(buf, 0, sizeof buf); sem_post(&sem_recv); /* tell sender we're ready */ if (multi) byt = lc_socket_multi_recv(lc_channel_socket(chan), buf, TEST_SIZE, 0, &dst); else byt = lc_channel_recv(chan, buf, TEST_SIZE, 0); if (byt == -1) perror("lc_channel_recv/lc_socket_multi_recv"); test_assert(byt == TEST_SIZE, "lc_channel_recv() returned %zi", byt); test_assert(memcmp(send_buf, buf, TEST_SIZE) == 0, "received data matches"); if (multi) test_assert(dst == chan, "destination channel matches channel pointer"); lc_keyring_free(&keyring); sem_post(&sem); /* tell ctrl thread we are finished */ return NULL; } static void *thread_send(void *arg) { lc_channel_t *chan = arg; ssize_t byt; lc_channel_setkey(chan, &ssk, LC_CODE_SIGN); /* send fake data without token */ byt = lc_channel_send(chan, fake_buf, sizeof fake_buf, 0); test_assert(byt == TEST_SIZE, "lc_channel_send() returned %zi", byt); /* set channel token */ lc_channel_setkey(chan, &ssk, LC_CODE_SIGN); /* reset correct signing key */ lc_channel_token_set(chan, &token); sem_wait(&sem_recv); /* wait for receiver to be ready */ byt = lc_channel_send(chan, send_buf, sizeof send_buf, 0); test_assert(byt == (ssize_t)TEST_SIZE, "lc_channel_send() returned %zi / %zi", byt, TEST_SIZE); return NULL; } static int create_token(lc_keypair_t *signerkey, lc_channel_t *chan) { /* create token */ struct timespec expires; int rc; clock_gettime(CLOCK_REALTIME, &expires); expires.tv_sec += TOKEN_SECONDS; rc = lc_token_new(&token, signerkey, senderpubkey, chan, capbits, TOKEN_SECONDS); /* verify token */ if (!test_assert(rc == 0, "lc_sign_keypair() - return value = %i", rc)) return -1; if (!test_assert(token.version == 0xff, "token: version set")) return -1; if (!test_assert(token.capbits == 42, "token: capbits set")) return -1; if (!test_assert(token.expires >= (uint64_t)expires.tv_sec, "token: expires set")) return -1; rc = memcmp(token.channel, lc_channel_get_hash(chan), sizeof token.channel); if (!test_assert(rc == 0, "token: channel set")) return -1; rc = memcmp(token.signkey, signerkey->pk, sizeof token.signkey); if (!test_assert(rc == 0, "token: signerkey set")) return -1; rc = memcmp(token.bearkey, senderpubkey, sizeof token.bearkey); if (!test_assert(rc == 0, "token: bearer key set")) return -1; rc = crypto_sign_verify_detached(token.sig, (unsigned char *)&token, 64, signerkey->pk); if (!test_assert(rc == 0, "token: signature OK")) return -1; /* publish token */ sendertoken = &token; return test_status; } static int generate_keys(lc_keypair_t *signerkey, lc_keypair_t *senderkey) { int rc; /* first, create signing keypair */ rc = lc_keypair_new(signerkey, LC_KEY_SIG); test_assert(rc == 0, "lc_keypair_new() - create signing keypair"); signerpubkey = signerkey->pk; /* publish signer public key */ /* create sender keypair */ rc = lc_keypair_new(senderkey, LC_KEY_SIG); test_assert(rc == 0, "lc_keypair_new() - create sender keypair"); senderpubkey = senderkey->pk; /* publish sender public key */ /* set secret signing key (sender) and bad (unauthorized) key */ ssk.key = senderkey->sk; ssk.keylen = crypto_sign_SECRETKEYBYTES; bad_ssk.key = signerkey->sk; bad_ssk.keylen = crypto_sign_SECRETKEYBYTES; /* generate symmetric encryption key */ if (enckey) crypto_secretbox_keygen(enckey); return test_status; } static void print_test_encodings(lc_socktype_t socktype, int encoding) { test_log("--------------------------------------------------------------------------------\n"); test_log("socket type: "); if (socktype & LC_SOCK_PAIR) test_log("socketpair\n"); else test_log("IPv6\n"); test_log("encryption: "); if (encoding & LC_CODE_SYMM) test_log("symmetric encryption\n"); else test_log("none\n"); test_log("encodings:"); if (encoding & LC_CODE_FEC_RQ) test_log(" RaptorQ"); if (encoding & LC_CODE_FEC_OTI) test_log(" OTI"); test_log("\n"); test_log("receiver API call: "); if (multi) test_log("lc_socket_multi_recv()\n"); else test_log("lc_channel_recv()\n"); test_log("--------------------------------------------------------------------------------\n"); } static int test_restricted(lc_socktype_t socktype, int encoding) { pthread_t tid[2]; lc_keypair_t senderkey; lc_ctx_t *lctx; lc_socket_t *sock[2]; lc_channel_t *chan[2]; int rc; print_test_encodings(socktype, encoding); /* prepare context, sockets, channels */ lctx = lc_ctx_new(); if (!test_assert(lctx != NULL, "lc_ctx_new()")) return test_status; if (socktype == LC_SOCK_IN6) { for (int i = 0; i < 2; i++) { sock[i] = lc_socket_new(lctx); if (!test_assert(sock[i] != NULL, "%i: lc_socket_new()", i)) goto free_lctx; rc = lc_socket_bind(sock[i], ifidx); if (rc == -1) perror("lc_socket_bind"); if (!test_assert(rc == 0, "%i: lc_socket_bind() ifx = %u", i, ifidx)) goto free_lctx; } rc = lc_socket_loop(sock[SEND], 1); if (!test_assert(rc == 0, "lc_socket_loop()")) goto free_lctx; } else if (socktype == LC_SOCK_PAIR) { rc = lc_socketpair(lctx, sock); if (!test_assert(rc == 0, "lc_socketpair()")) goto free_lctx; } else goto free_lctx; for (int i = 0; i < 2; i++) { chan[i] = lc_channel_new(lctx, TEST_NAME); if (!test_assert(chan[i] != NULL, "%i: lc_channel_new()", i)) goto free_lctx; test_log("chan[%i]: %p\n", i, (void *)chan[i]); rc = lc_channel_bind(sock[i], chan[i]); if (!test_assert(rc == 0, "lc_channel_bind()")) goto free_lctx; if (encoding) lc_channel_coding_set(chan[i], encoding); } rc = lc_channel_join(chan[RECV]); if (!test_assert(rc == 0, "lc_channel_join()")) goto free_lctx; if (encoding & LC_CODE_FEC_RQ) lc_channel_rq_overhead(chan[SEND], RQ_OVERHEAD * 2); lc_channel_ratelimit(chan[SEND], SPEED_LIMIT, 0); /* generate keys and tokens */ if (encoding & LC_CODE_SYMM) { enckey = malloc(crypto_secretbox_KEYBYTES); if (!enckey) goto free_lctx; for (int i = 0; i < 2; i++) { lc_channel_set_sym_key(chan[i], enckey, crypto_secretbox_KEYBYTES); } } if (generate_keys(&signerkey, &senderkey)) goto free_lctx; if (create_token(&signerkey, chan[0])) goto free_lctx; /* generate test data */ arc4random_buf(send_buf, sizeof send_buf); arc4random_buf(fake_buf, sizeof fake_buf); /* start threads */ void *(*thread_f[2])(void *) = { &thread_recv, &thread_send }; int threads = 0; rc = sem_init(&sem, 0, 0); if (!test_assert(rc == 0, "sem_init()")) goto free_lctx; rc = sem_init(&sem_recv, 0, 0); if (!test_assert(rc == 0, "sem_init()")) goto free_sem; for (int i = 0; i < 2; i++) { rc = pthread_create(&tid[i], NULL, thread_f[i], chan[i]); if (!test_assert(rc == 0, "%i: pthread_create", i)) goto join_threads; threads++; } /* timeout */ struct timespec ts; if (!test_assert(!clock_gettime(CLOCK_REALTIME, &ts), "clock_gettime()")) goto join_threads; ts.tv_sec += WAITS; test_assert(!sem_timedwait(&sem, &ts), "timeout"); join_threads: for (int i = 0; i < threads; i++) { pthread_cancel(tid[i]); pthread_join(tid[i], NULL); } sem_destroy(&sem_recv); free_sem: sem_destroy(&sem); free_lctx: free(enckey); enckey = NULL; lc_ctx_free(lctx); return test_status; } #endif int main(void) { char name[] = TEST_NAME; #if defined(HAVE_LIBLCRQ) && (HAVE_LIBSODIUM) test_name(name); test_require_net(TEST_NET_BASIC); ifidx = get_multicast_if(); if (!test_assert(ifidx > 0, "get_multicast_if()")) return test_status; /* test different socket types and symmetric encryption with different encodings */ for (lc_socktype_t i = 0; i <= LC_SOCK_PAIR; i++) { for (lc_coding_t e = 0; e <= LC_CODE_SYMM; e++) { /* multi = 0 => use lc_channel_recv() * multi = 1 => use lc_socket_multi_recv() */ for (multi = 0; multi < 2; multi++) { if (test_restricted(i, e | LC_CODE_NONE)) return test_status; if (test_restricted(i, e | LC_CODE_FEC_RQ)) return test_status; if (test_restricted(i, e | LC_CODE_FEC_RQ | LC_CODE_FEC_OTI)) return test_status; if (test_restricted(i, LC_CODE_FEC_RQ | LC_CODE_FEC_OTI)) return test_status; } } } return test_status; #else return test_skip("%s - requires libsodium", name); #endif } librecast/test/0000-0100.c000066400000000000000000000031511502456746400151230ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2023 Brett Sheffield */ #include "test.h" #include "testdata.h" #include #include #define TEST_SIZE 42 * 1024 + 1 /* nice powers of two hide bugs - ensure test size is odd */ _Static_assert(TEST_SIZE % 2, "TEST_SIZE must be an odd number"); int main(void) { uint8_t *src, *dst; int rc; test_name("lc_memsync()"); rc = lc_memsync(NULL, NULL, 0, NULL, NULL, NULL, 0); test_assert(rc == -1, "size must be greater than zero"); /* allocate some memory to work with */ src = malloc(TEST_SIZE); test_assert(src != NULL, "allocate source"); if (!src) return TEST_FAIL; dst = malloc(TEST_SIZE); memset(dst, 0, TEST_SIZE); test_assert(dst != NULL, "allocate destination"); test_assert(!test_random_bytes(src, TEST_SIZE), "randomize src"); test_assert(memcmp(dst, src, TEST_SIZE), "dst and src differ"); /* sync */ rc = lc_memsync(dst, src, TEST_SIZE, NULL, NULL, NULL, 0); test_assert(rc == 0, "lc_memsync() returns 0 (SUCCESS)"); test_assert(!memcmp(dst, src, TEST_SIZE), "dst matches src"); /* scratch source, sync again */ test_assert(!test_random_bytes(src, 1), "scratch src"); test_assert(!test_random_bytes(src + 5 * 1024, 3), "scratch src"); test_assert(!test_random_bytes(src + 15 * 1024, 3), "scratch src"); test_assert(memcmp(dst, src, TEST_SIZE), "dst and src differ"); test_assert(!lc_memsync(dst, src, TEST_SIZE, NULL, NULL, NULL, 0), "lc_memsync"); test_assert(!memcmp(dst, src, TEST_SIZE), "dst matches src"); /* clean up */ free(dst); free(src); return test_status; } librecast/test/0000-0101.c000066400000000000000000000024441502456746400151300ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2021-2023 Brett Sheffield */ #include "test.h" #include #include int main(void) { size_t node, parent; test_name("mtree_parent()"); node = 0; parent = -1; test_assert(mtree_parent(node) == parent, "mtree_parent(%zu) => %zu", node, parent); node = 1; parent = 0; test_assert(mtree_parent(node) == parent, "mtree_parent(%zu) => %zu", node, parent); node = 2; parent = 0; test_assert(mtree_parent(node) == parent, "mtree_parent(%zu) => %zu", node, parent); node = 3; parent = 1; test_assert(mtree_parent(node) == parent, "mtree_parent(%zu) => %zu", node, parent); node = 4; parent = 1; test_assert(mtree_parent(node) == parent, "mtree_parent(%zu) => %zu", node, parent); node = 5; parent = 2; test_assert(mtree_parent(node) == parent, "mtree_parent(%zu) => %zu", node, parent); node = 6; parent = 2; test_assert(mtree_parent(node) == parent, "mtree_parent(%zu) => %zu", node, parent); node = 7; parent = 3; test_assert(mtree_parent(node) == parent, "mtree_parent(%zu) => %zu", node, parent); node = 16; parent = 7; test_assert(mtree_parent(node) == parent, "mtree_parent(%zu) => %zu", node, parent); return test_status; } librecast/test/0000-0110.c000066400000000000000000000071631502456746400151330ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2023-2024 Brett Sheffield */ #include "test.h" #include "testdata.h" #include "testnet.h" #include #include #include #include #include #if HAVE_RQ_OTI #define TEST_SIZE MTREE_CHUNKSIZE * 100 + 5 /* nice powers of two hide bugs - ensure test size is odd */ _Static_assert(TEST_SIZE % 2, "TEST_SIZE must be an odd number"); #define TIMEOUT_SECONDS 60 enum { TID_SEND, TID_RECV }; static sem_t sem_recv; struct pkg_s { void *data; size_t len; uint8_t *hash; }; void *thread_recv(void *arg) { struct pkg_s *pkg = (struct pkg_s *)arg; lc_ctx_t *lctx = lc_ctx_new(); pthread_cleanup_push((void (*)(void *))lc_ctx_free, lctx); lc_recvchunk(lctx, pkg->hash, pkg->data, pkg->len, NULL, NULL, 0); pthread_cleanup_pop(1); /* lc_ctx_free */ sem_post(&sem_recv); return NULL; } void *thread_send(void *arg) { struct pkg_s *pkg = (struct pkg_s *)arg; lc_ctx_t *lctx = lc_ctx_new(); pthread_cleanup_push((void (*)(void *))lc_ctx_free, lctx); lc_sendchunk(lctx, pkg->hash, pkg->data, pkg->len, NULL, NULL, NET_LOOPBACK); pthread_cleanup_pop(1); return NULL; } #endif /* HAVE_RQ_OTI */ int main(void) { char name[] = "lc_sendchunk()/lc_recvchunk()"; #if HAVE_RQ_OTI uint8_t *src, *dst; struct pkg_s pkg_send = {0}, pkg_recv = {0}; pthread_t tid[2]; struct timespec timeout = {0}; int rc; test_name(name); test_require_net(TEST_NET_BASIC); /* allocate some memory to work with */ src = malloc(TEST_SIZE); test_assert(src != NULL, "allocate source"); if (!src) return test_status; dst = malloc(TEST_SIZE); test_assert(dst != NULL, "allocate destination"); if (!dst) goto err_free_src; memset(dst, 0, TEST_SIZE); test_assert(!test_random_bytes(src, TEST_SIZE), "randomize src"); test_assert(memcmp(dst, src, TEST_SIZE), "dst and src differ"); if (test_status != TEST_OK) goto err_free_dst; /* find hash of source */ mtree_t stree = {0}; rc = mtree_init(&stree, TEST_SIZE); if (!test_assert(rc == 0, "mtree_init returned %i", rc)) goto err_free_dst; mtree_build(&stree, src, NULL); /* sync */ rc = sem_init(&sem_recv, 0, 0); if (!test_assert(rc == 0, "sem_init returned %i", rc)) goto err_free_stree; /* start send thread */ pkg_send.data = src; pkg_send.len = TEST_SIZE; pkg_send.hash = stree.tree; rc = pthread_create(&tid[TID_SEND], NULL, thread_send, &pkg_send); if (!test_assert(rc == 0, "pthread_create(TID_SEND) returned %i", rc)) goto err_sem_recv_destroy; /* start recv thread */ pkg_recv.data = dst; pkg_recv.len = TEST_SIZE; pkg_recv.hash = stree.tree; rc = pthread_create(&tid[TID_RECV], NULL, thread_recv, &pkg_recv); if (!test_assert(rc == 0, "pthread_create(TID_RECV) returned %i", rc)) goto err_cancel_tid_send; /* handle timeout */ rc = clock_gettime(CLOCK_REALTIME, &timeout); if (!test_assert(rc == 0, "clock_gettime returned %i", rc)) goto err_cancel_tid_recv; timeout.tv_sec += TIMEOUT_SECONDS; if ((rc = sem_timedwait(&sem_recv, &timeout)) == -1 && errno == ETIMEDOUT) { test_assert(0, "timeout waiting for recv thread"); goto err_cancel_tid_recv; } /* check what we received */ test_assert(!memcmp(dst, src, TEST_SIZE), "dst matches src"); /* clean up */ err_cancel_tid_recv: pthread_cancel(tid[TID_RECV]); pthread_join(tid[TID_RECV], NULL); err_cancel_tid_send: pthread_cancel(tid[TID_SEND]); pthread_join(tid[TID_SEND], NULL); err_sem_recv_destroy: sem_destroy(&sem_recv); err_free_stree: mtree_free(&stree); err_free_dst: free(dst); err_free_src: free(src); return test_status; #else return test_skip(name); #endif } librecast/test/0000-0111.c000066400000000000000000000064241502456746400151330ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2023-2024 Brett Sheffield */ #include "testnet.h" #include "testdata.h" #include #include #include #include #include #if HAVE_RQ_OTI #define TEST_SIZE MTREE_CHUNKSIZE * 100 + 5 /* nice powers of two hide bugs - ensure test size is odd */ _Static_assert(TEST_SIZE % 2, "TEST_SIZE must be an odd number"); #define TIMEOUT_SECONDS 2 enum { TID_SEND, TID_RECV }; static sem_t sem_recv; struct pkg_s { void *data; size_t len; uint8_t *hash; mtree_t tree; }; void *thread_recv(void *arg) { struct pkg_s *pkg = (struct pkg_s *)arg; lc_ctx_t *lctx = lc_ctx_new(); pthread_cleanup_push((void (*)(void *))lc_ctx_free, lctx); lc_recvtree(lctx, pkg->hash, &pkg->tree, NULL, NULL, 0); pthread_cleanup_pop(1); /* lc_ctx_free */ sem_post(&sem_recv); return NULL; } void *thread_send(void *arg) { struct pkg_s *pkg = (struct pkg_s *)arg; lc_ctx_t *lctx = lc_ctx_new(); pthread_cleanup_push((void (*)(void *))lc_ctx_free, lctx); lc_sendtree(lctx, pkg->hash, &pkg->tree, NULL, NULL, NET_LOOPBACK); pthread_cleanup_pop(1); /* lc_ctx_free */ return NULL; } #endif int main(void) { char name[] = "lc_sendtree()/lc_recvtree()"; #if HAVE_RQ_OTI uint8_t *src, *dst; struct pkg_s pkg_send = {0}, pkg_recv = {0}; pthread_t tid[2]; struct timespec timeout = {0}; test_name(name); test_require_net(TEST_NET_BASIC); /* allocate some memory to work with */ src = malloc(TEST_SIZE); test_assert(src != NULL, "allocate source"); if (!src) return TEST_FAIL; dst = malloc(TEST_SIZE); memset(dst, 0, TEST_SIZE); test_assert(dst != NULL, "allocate destination"); if (!dst) return TEST_FAIL; test_assert(!test_random_bytes(src, TEST_SIZE), "randomize src"); /* find hash of source */ mtree_init(&pkg_send.tree, TEST_SIZE); mtree_build(&pkg_send.tree, src, NULL); /* sync */ /* start send thread */ pkg_send.data = src; pkg_send.len = TEST_SIZE; pkg_send.hash = pkg_send.tree.tree; pthread_create(&tid[TID_SEND], NULL, thread_send, &pkg_send); /* start recv thread */ sem_init(&sem_recv, 0, 0); pkg_recv.data = dst; pkg_recv.len = TEST_SIZE; pkg_recv.hash = pkg_send.tree.tree; pthread_create(&tid[TID_RECV], NULL, thread_recv, &pkg_recv); /* handle timeout */ clock_gettime(CLOCK_REALTIME, &timeout); timeout.tv_sec += TIMEOUT_SECONDS; int ret; if ((ret = sem_timedwait(&sem_recv, &timeout)) == -1 && errno == ETIMEDOUT) { for (int i = 0; i < 2; i++) pthread_cancel(tid[i]); } pthread_cancel(tid[TID_SEND]); test_assert(ret == 0, "timeout waiting for recv thread"); sem_destroy(&sem_recv); /* stop threads */ for (int i = 0; i < 2; i++) pthread_join(tid[i], NULL); /* check what we received */ test_assert(mtree_verify(&pkg_recv.tree) == 0, "verify received tree"); test_assert(!memcmp(pkg_recv.tree.tree, pkg_send.tree.tree, pkg_send.tree.nodes * HASHSIZE), "trees match"); test_log("tree->nodes = %zu\n", pkg_recv.tree.nodes); test_log("tree->len = %zu\n", pkg_recv.tree.len); test_log("tree->chunks = %zu\n", pkg_recv.tree.chunks); /* clean up */ mtree_free(&pkg_send.tree); mtree_free(&pkg_recv.tree); free(dst); free(src); return test_status; #else return test_skip(name); #endif /* HAVE_RQ_OTI */ } librecast/test/0000-0112.c000066400000000000000000000116241502456746400151320ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2021-2023 Brett Sheffield */ #include "test.h" #include "testdata.h" #include #include #include #include int main(void) { struct stat sb_orig, sb; char src[] = "0000-0112.src.tmp.XXXXXX"; char dst[] = "0000-0112.dst.tmp.XXXXXX"; const off_t len = 1000; const size_t sz_s = 1024 * 10 + 13; const size_t extra = 999; size_t newlen; size_t off; int fds, rc; test_name("lc_syncfilelocal()"); /* create test file */ fds = test_data_file(src, sz_s, TEST_TMP | TEST_RND); test_assert(fds != -1, "test_data_file()"); if (fds == -1) goto exit_0; test_assert(test_data_size(src, sz_s) == 0, "source exists and is correct size"); test_assert(stat(src, &sb_orig) != -1, "stat source file"); /* set destination filename */ off = strlen(src) - 6; memcpy(dst + off, src + off, 6); /* sync files */ test_assert(lc_syncfilelocal(dst, src, NULL, NULL, NULL, 0) == 0, "lc_syncfilelocal()"); /* verify data matches */ test_assert(test_data_size(dst, sz_s) == 0, "destination exists and is correct size"); test_assert(test_file_match(dst, src) == 0, "source and destination data matches"); test_assert(stat(src, &sb) != -1, "stat source file"); test_assert(sb.st_mode == sb_orig.st_mode, "source file mode unchanged"); test_assert(stat(dst, &sb) != -1, "stat destination file"); test_assert(sb.st_mode == sb_orig.st_mode, "dest file mode set correctly"); test_log("\nscratch the source, re-sync, check again\n"); test_file_scratch(src, 10, 1); test_assert(test_file_match(dst, src) != 0, "source and destination data no longer match"); test_assert(lc_syncfilelocal(dst, src, NULL, NULL, NULL, 0) == 0, "lc_syncfilelocal()"); test_assert(test_data_size(dst, sz_s) == 0, "destination exists and is correct size"); test_assert(test_file_match(dst, src) == 0, "source and destination data matches"); test_log("\nscratch the destination, re-sync, check again\n"); test_file_scratch(dst, 999, 42); test_assert(test_file_match(dst, src) != 0, "source and destination data no longer match"); test_assert(lc_syncfilelocal(dst, src, NULL, NULL, NULL, 0) == 0, "lc_syncfilelocal()"); test_assert(test_data_size(dst, sz_s) == 0, "destination exists and is correct size"); test_assert(test_file_match(dst, src) == 0, "source and destination data matches"); test_log("\ntruncate the destination, re-sync, check again\n"); test_assert(truncate(dst, len) == 0, "truncating destination to %zu bytes", (size_t)len); test_assert(test_data_size(dst, len) == 0, "destination exists and is truncated"); test_assert(test_file_match(dst, src) != 0, "source and destination data no longer match"); test_assert(lc_syncfilelocal(dst, src, NULL, NULL, NULL, 0) == 0, "lc_syncfilelocal()"); test_assert(test_data_size(dst, sz_s) == 0, "destination exists and is correct size"); test_assert(test_file_match(dst, src) == 0, "source and destination data matches"); test_log("\ntruncate the source, re-sync, check again\n"); test_assert(truncate(src, len) == 0, "truncating source to %zu bytes", (size_t)len); test_assert(test_data_size(src, len) == 0, "source exists and is truncated"); test_assert(test_file_match(dst, src) != 0, "source and destination data no longer match"); rc = lc_syncfilelocal(dst, src, NULL, NULL, NULL, 0); test_assert(rc == 0, "lc_syncfilelocal() returned %i", rc); test_assert(test_data_size(dst, len) == 0, "destination exists and is new size"); test_assert(test_file_match(dst, src) == 0, "source and destination data matches"); test_log("\nextend the source (sparse), re-sync, check again\n"); newlen = sz_s + len; test_sparsify_fd(fds, newlen); test_assert(test_data_size(src, newlen) == 0, "source exists and is new length"); rc = lc_syncfilelocal(dst, src, NULL, NULL, NULL, 0); test_assert(rc == 0, "lc_syncfilelocal() returned %i", rc); test_assert(test_data_size(dst, newlen) == 0, "destination exists and is new size"); test_assert(test_file_match(dst, src) == 0, "source and destination data matches"); test_log("\nextend the source (append random data), re-sync, check again\n"); test_file_scratch(src, newlen, extra); /* extend with random data */ newlen += extra; test_assert(test_data_size(src, newlen) == 0, "source exists and is new length"); test_assert(lc_syncfilelocal(dst, src, NULL, NULL, NULL, 0) == 0, "lc_syncfilelocal()"); test_assert(test_data_size(dst, newlen) == 0, "destination exists and is new size"); test_assert(test_file_match(dst, src) == 0, "source and destination data matches"); test_assert(stat(src, &sb) != -1, "stat source file"); test_assert(sb.st_mode == sb_orig.st_mode, "source file mode unchanged"); test_assert(stat(dst, &sb) != -1, "stat destination file"); test_assert(sb.st_mode == sb_orig.st_mode, "dest file mode set correctly"); /* clean up, delete test files */ close(fds); unlink(dst); unlink(src); exit_0: return test_status; } librecast/test/0000-0113.c000066400000000000000000000154511502456746400151350ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2023 Brett Sheffield */ #define _DEFAULT_SOURCE /* be64toh */ #define _XOPEN_SOURCE 700 /* for nftw() */ #include "test.h" #include "testdata.h" #include #include #include #include #include #include #include #include #include #include #define MAXFILESZ 1048576 #define MAXFILES 10 #define MAXDIRS 5 #define DEPTH 3 typedef struct srclistentry_s srclistentry_t; struct srclistentry_s { char *fpath; struct stat sb; int type; srclistentry_t *next; }; static srclistentry_t *srclist_head; static srclistentry_t *srclist_last; static void free_srclist(srclistentry_t *list) { srclistentry_t *tmp; while (list) { free(list->fpath); tmp = list; list = list->next; free(tmp); } } static int build_srclist(const char *fpath, const struct stat *sb, int typeflag, struct FTW *ftwbuf) { (void)ftwbuf; srclistentry_t *entry = calloc(1, sizeof(srclistentry_t)); entry->sb = *sb; entry->type = typeflag; entry->fpath = strdup(fpath); if (!srclist_head) { srclist_head = entry; srclist_last = entry; } else { srclist_last->next = entry; srclist_last = entry; } return 0; } static int verify_filemeta(mdex_entry_t *entry) { struct stat sb; int rc; if (!test_assert(entry->file.file.name != NULL, "file name buffer allocated")) return -1; if (!test_assert(entry->file.file.sb != NULL, "file stat buffer allocated")) return -1; rc = stat(entry->file.file.name, &sb); test_assert(rc == 0, "stat '%s'", entry->file.file.name); /* atime is changed by the call to stat(), so forcibly set it before * comparing the rest of the stat buffer */ sb.st_atim.tv_sec = entry->file.file.sb->st_atim.tv_sec; sb.st_atim.tv_nsec = entry->file.file.sb->st_atim.tv_nsec; test_assert(!memcmp(&sb, entry->file.file.sb, sizeof sb), "stat buffer matches"); return test_status; } static int verify_file(mdex_t *mdex, mdex_entry_t *entry) { net_tree_t *data; mtree_t mtree; unsigned char *hash; size_t min, max; int rc; /* files are stored as pointers to their mtree with an OTI flag */ if (!test_assert(entry->type == (MDEX_PTR | MDEX_OTI), "entry is file: 0x%08x", entry->type)) return -1; /* verify tree */ if (!test_assert(entry->ptr.data != NULL, "file mtree data allocated")) return -1; data = (net_tree_t *)entry->ptr.data; data->size = be64toh(data->size); data->namesz = ntohs(data->namesz); rc = mtree_init(&mtree, data->size); if (!test_assert(rc == 0, "mtree_init()")) return -1; test_log("mtree.nodes=%zu, HASHSIZE=%zu\n", mtree.nodes, HASHSIZE); test_log("tree has size %" PRIu64 ", hashsz=%zu\n", data->size, (size_t)mtree.nodes * (size_t)HASHSIZE); assert(data->size < UINT32_MAX); /* none of our trees are that large */ memcpy(mtree.tree, data->tree + data->namesz, (size_t)mtree.nodes * (size_t)HASHSIZE); rc = mtree_verify(&mtree); if (!test_assert(rc == 0, "mtree_verify()")) goto err_mtree_free; /* check data chunks are indexed */ if (!test_assert(mtree.len > 0, "tree has len %zu", mtree.len)) goto err_mtree_free; if (!test_assert(mtree.base > 0, "tree has base %zu", mtree.base)) goto err_mtree_free; if (!test_assert(mtree.chunks > 0, "tree has chunks %zu", mtree.chunks)) goto err_mtree_free; min = mtree_subtree_data_min(mtree.base, 0); max = min + mtree.chunks - 1; test_log("testing index for chunks %zu to %zu\n", min, max); for (size_t z = min; z <= max; z++) { hash = mtree_nnode(&mtree, z); rc = mdex_get(mdex, hash, HASHSIZE, entry); if (!test_assert(rc == 0, "mdex_get() found chunk %zu", z)) goto err_mtree_free; if (z == 0 && !verify_filemeta(entry)) break; } err_mtree_free: mtree_free(&mtree); return test_status; } static int verify_dir(mdex_t *mdex, mdex_entry_t *entry) { struct stat sb; mdex_entry_t mentry; mdex_hash_t *dir = entry->file.file.dir; int rc; if (!test_assert(entry->type & MDEX_DIR, "entry is dir: 0x%08x", entry->type)) return -1; if (!test_assert(entry->file.file.name != NULL, "directory name buffer allocated")) return -1; if (!test_assert(entry->file.file.sb != NULL, "directory stat buffer allocated")) return -1; rc = stat(entry->file.file.name, &sb); test_assert(rc == 0, "stat '%s'", entry->file.file.name); /* atime is changed by the call to stat(), so forcibly set it before * comparing the rest of the stat buffer */ sb.st_atim.tv_sec = entry->file.file.sb->st_atim.tv_sec; sb.st_atim.tv_nsec = entry->file.file.sb->st_atim.tv_nsec; test_assert(!memcmp(&sb, entry->file.file.sb, sizeof sb), "stat buffer matches"); /* fetch each directory entry hash from mdex, * stat each file and check attributes */ for (size_t i = 0; i < entry->file.size; i++) { rc = mdex_get(mdex, dir[i], sizeof(mdex_hash_t), &mentry); if (!test_assert(rc == 0, "checking dir entry %i: mdex_get() returned %i", i, rc)) return -1; switch (mentry.type & 0xffff) { case MDEX_DIR: if (verify_dir(mdex, &mentry)) return -1; break; case MDEX_PTR: if (verify_file(mdex, &mentry)) return -1; break; default: return -1; } } return 0; } static int verify_entry(mdex_t *mdex, srclistentry_t *src) { mdex_entry_t entry; int rc = mdex_getalias(mdex, src->fpath, &entry); test_assert(rc == 0, "%s: '%s'", __func__, src->fpath); return rc; } int main(int argc, char *argv[]) { (void)argc; mdex_t *mdex; char *src = NULL, *dst = NULL; int rc; test_name("mdex_addfile() - recursive file indexing"); /* create source directory tree and files */ rc = test_createtestdirs(basename(argv[0]), &src, &dst); if (!test_assert(rc == 0, "test_createtestdirs()")) return test_status; rc = test_createtesttree(src, MAXFILESZ, MAXFILES, MAXDIRS, DEPTH, 0); if (!test_assert(rc == 0, "test_createtesttree()")) goto err_free_src_dst; /* create a list to test against */ rc = nftw(src, &build_srclist, 32, 0); if (!test_assert(rc == 0, "nftw() returned %i", rc)) goto err_free_src_dst; /* index source tree */ mdex = mdex_init(512); if (!test_assert(mdex != NULL, "mdex_init()")) goto err_free_srclist; rc = mdex_addfile(mdex, src, NULL, MDEX_RECURSE); if (!test_assert(rc == 0, "mdex_addfile() returned %i", rc)) goto err_mdex_free; /* verify files have been added */ for (srclistentry_t *e = srclist_head; e; e = e->next) { if (verify_entry(mdex, e)) break; } /* recursively verify tree */ test_log("recursively verify tree\n"); mdex_entry_t entry; rc = mdex_getalias(mdex, src, &entry); if (!test_assert(rc == 0, "mdex_getalias() - found base tree dir '%s'", src)) goto err_mdex_free; rc = verify_dir(mdex, &entry); test_assert(rc == 0, "directory tree verified"); err_mdex_free: mdex_free(mdex); err_free_srclist: free_srclist(srclist_head); err_free_src_dst: free(src); free(dst); return test_status; } librecast/test/0000-0114.c000066400000000000000000000036041502456746400151330ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2023 Brett Sheffield */ #define _DEFAULT_SOURCE /* be64toh */ #define _XOPEN_SOURCE 700 /* for nftw() */ #include "test.h" #include "testdata.h" #include "testsync.h" #include #include #include #include #include #include #include #include #include #define MAXFILESZ 1048576 #define MAXFILES 10 #define MAXDIRS 5 #define DEPTH 2 /* * test 0114 * * create a tree of files and directories and use lc_syncfilelocal() to sync * recursively to destination directory. * * Compare the resulting directories and ensure they match. */ int main(int argc, char *argv[]) { (void)argc; char *src = NULL, *dst = NULL; const int flags = SYNC_RECURSE | SYNC_ATIME | SYNC_MTIME | SYNC_OWNER | SYNC_GROUP | SYNC_MODE; int rc; test_name("lc_syncfilelocal() - recursive file syncing"); /* create source directory tree and files */ rc = test_createtestdirs(basename(argv[0]), &src, &dst); if (!test_assert(rc == 0, "test_createtestdirs()")) return test_status; rc = test_createtesttree(src, MAXFILESZ, MAXFILES, MAXDIRS, DEPTH, 0); if (!test_assert(rc == 0, "test_createtesttree()")) goto err_free_src_dst; #if 0 /* XXX; match src and dst match */ char cmd[128]; //snprintf(cmd, sizeof cmd, "rsync -avq %s/ %s", src, dst); snprintf(cmd, sizeof cmd, "cp -Rp %s/. %s", src, dst); test_log("`%s`\n", cmd); if (system(cmd)) { test_assert(0, "cmd failed"); goto err_free_src_dst; } #endif /* sync dst from src */ rc = lc_syncfilelocal(dst, src, NULL, NULL, NULL, flags); if (!test_assert(rc == 0, "lc_syncfilelocal() returned %i", rc)) goto err_free_src_dst; /* verify src and dst match */ test_verify_dirs(src, dst); err_free_src_dst: free(src); free(dst); return test_status; } librecast/test/0000-0115.c000066400000000000000000000166311502456746400151400ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2023-2025 Brett Sheffield */ #define _DEFAULT_SOURCE /* be64toh */ #define _XOPEN_SOURCE 700 /* for nftw() */ #include "test.h" #include "testdata.h" #include "testnet.h" #include #include #include #include #include #include #include #include #include #include #if HAVE_RQ_OTI #define MAXFILESZ 1048576 #define MAXFILES 2 #define MAXDIRS 2 #define DEPTH 2 #define TIMEOUT_SECONDS 2 enum { TID_SEND, TID_RECV }; static sem_t sem_recv; struct pkg_s { net_tree_t **data; size_t len; unsigned char *hash; }; typedef struct srclistentry_s srclistentry_t; struct srclistentry_s { char *fpath; struct stat sb; int type; srclistentry_t *next; }; static srclistentry_t *srclist_head; static srclistentry_t *srclist_last; void *thread_recv(void *arg) { struct pkg_s *pkg = (struct pkg_s *)arg; lc_ctx_t *lctx; ssize_t rc; test_log("%s starting\n", __func__); lctx = lc_ctx_new(); if (!test_assert(lctx != NULL, "%s() lc_ctx_new", __func__)) goto err_sem_post; pthread_cleanup_push((void (*)(void *))lc_ctx_free, lctx); hash_hex_debug(stderr, pkg->hash, HASHSIZE); rc = lc_recvdir(lctx, pkg->hash, pkg->data, NULL, NULL, 0); test_assert(rc > 0, "lc_recvdir() returned %zi", rc); pthread_cleanup_pop(1); /* lc_ctx_free */ err_sem_post: sem_post(&sem_recv); return NULL; } void *thread_send(void *arg) { struct pkg_s *pkg = (struct pkg_s *)arg; ssize_t rc; lc_ctx_t *lctx; test_log("%s starting\n", __func__); lctx = lc_ctx_new(); if (!test_assert(lctx != NULL, "%s() lc_ctx_new", __func__)) return NULL; pthread_cleanup_push((void (*)(void *))lc_ctx_free, lctx); rc = lc_senddir(lctx, pkg->hash, *(pkg->data), NULL, NULL, NET_LOOPBACK); test_assert(rc > 0, "lc_senddir() returned %zi", rc); pthread_cleanup_pop(1); /* lc_ctx_free */ return NULL; } static void free_srclist(srclistentry_t *list) { srclistentry_t *tmp; while (list) { free(list->fpath); tmp = list; list = list->next; free(tmp); } } static int build_srclist(const char *fpath, const struct stat *sb, int typeflag, struct FTW *ftwbuf) { (void)ftwbuf; srclistentry_t *entry = calloc(1, sizeof(srclistentry_t)); entry->sb = *sb; entry->type = typeflag; entry->fpath = strdup(fpath); if (!srclist_head) { srclist_head = entry; srclist_last = entry; } else { srclist_last->next = entry; srclist_last = entry; } return 0; } static int verify_dir(net_tree_t *sdir, net_tree_t *ddir) { if (!test_assert(sdir != NULL, "sdir != NULL")) return -1; if (!test_assert(ddir != NULL, "ddir != NULL")) return -1; if (!test_assert(sdir->size > 0, "directory size > 0")) return -1; sdir->size = htobe64(sdir->size); if (!test_assert(sdir->size == ddir->size, "directory sizes match (%zu == %zu)", sdir->size, ddir->size)) return -1; if (!test_assert(!memcmp(sdir->tree, ddir->tree, sdir->size), "dir hashes match")) return -1; if (!test_assert(sdir->atime_s == ddir->atime_s, "atime (sec) matches")) return -1; if (!test_assert(sdir->atime_n == ddir->atime_n, "atime (nsec) matches")) return -1; if (!test_assert(sdir->mtime_s == ddir->mtime_s, "mtime (sec) matches")) return -1; if (!test_assert(sdir->mtime_n == ddir->mtime_n, "mtime (nsec) matches")) return -1; if (!test_assert(sdir->mode == ddir->mode, "mode matches")) return -1; if (!test_assert(sdir->uid == ddir->uid, "uid matches")) return -1; if (!test_assert(sdir->gid == ddir->gid, "gid matches")) return -1; return 0; } static int verify_entry(mdex_t *mdex, srclistentry_t *src) { mdex_entry_t entry; int rc = mdex_getalias(mdex, src->fpath, &entry); test_assert(rc == 0, "%s: '%s'", __func__, src->fpath); return rc; } #endif /* HAVE_RQ_OTI */ int main(int argc, char *argv[]) { (void)argc, (void)argv; char name[] = "lc_senddir()/lc_recvdir()"; #if HAVE_RQ_OTI pthread_t tid[2]; struct pkg_s pkg_send = {0}, pkg_recv = {0}; struct timespec timeout = {0}; mdex_t *mdex; char *src = NULL, *dst = NULL; net_tree_t *sdir, *ddir; int rc; test_name(name); test_require_net(TEST_NET_BASIC); /* create source directory tree and files */ rc = test_createtestdirs(basename(argv[0]), &src, &dst); if (!test_assert(rc == 0, "test_createtestdirs()")) return test_status; rc = test_createtesttree(src, MAXFILESZ, MAXFILES, MAXDIRS, DEPTH, 0); if (!test_assert(rc == 0, "test_createtesttree()")) goto err_free_src_dst; /* create a list to test against */ rc = nftw(src, &build_srclist, 32, 0); if (!test_assert(rc == 0, "nftw() returned %i", rc)) goto err_free_src_dst; /* index source tree */ mdex = mdex_init(512); if (!test_assert(mdex != NULL, "mdex_init()")) goto err_free_srclist; rc = mdex_addfile(mdex, src, NULL, MDEX_RECURSE); if (!test_assert(rc == 0, "mdex_addfile() returned %i", rc)) goto err_mdex_free; /* verify files have been added */ for (srclistentry_t *e = srclist_head; e; e = e->next) { if (verify_entry(mdex, e)) break; } /* sync */ /* prepare directory for sending */ mdex_entry_t entry; sdir = NULL; ddir = NULL; rc = mdex_getalias(mdex, src, &entry); if (!test_assert(rc == 0, "mdex_getalias() - found base tree dir '%s'", src)) goto err_mdex_free; size_t treesz = sizeof(hash_t) * entry.file.size; size_t sz = sizeof(struct net_tree_s) + treesz; sdir = malloc(sz); if (!test_assert(sdir != NULL, "malloc(sdir)")) goto err_mdex_free; memset(sdir, 0, sz); sdir->size = entry.file.size * HASHSIZE; memcpy(sdir->tree, entry.file.file.dir, treesz); sdir->mode = entry.file.file.sb->st_mode; sdir->uid = entry.file.file.sb->st_uid; sdir->gid = entry.file.file.sb->st_gid; sdir->atime_s = entry.file.file.sb->st_atim.tv_sec; sdir->atime_n = entry.file.file.sb->st_atim.tv_nsec; sdir->mtime_s = entry.file.file.sb->st_mtim.tv_sec; sdir->mtime_n = entry.file.file.sb->st_mtim.tv_nsec; test_assert(sdir->uid != 0, "uid set = %i", sdir->uid); test_assert(sdir->gid != 0, "gid set = %i", sdir->gid); test_assert(sdir->mode != 0, "mode set = %i", sdir->mode); test_assert(sdir->atime_s != 0, "atime.tv_sec set = %i", sdir->atime_s); test_assert(sdir->mtime_s != 0, "mtime.tv_sec set = %i", sdir->mtime_s); unsigned char dirhash[HASHSIZE]; hash_generic(dirhash, sizeof dirhash, (unsigned char *)src, strlen(src)); test_log("dirhash: "); hash_hex_debug(stderr, dirhash, HASHSIZE); /* start send thread */ pkg_send.data = &sdir; pkg_send.hash = dirhash; pthread_create(&tid[TID_SEND], NULL, thread_send, &pkg_send); /* start recv thread */ sem_init(&sem_recv, 0, 0); pkg_recv.data = &ddir; pkg_recv.hash = dirhash; pthread_create(&tid[TID_RECV], NULL, thread_recv, &pkg_recv); /* handle timeout */ clock_gettime(CLOCK_REALTIME, &timeout); timeout.tv_sec += TIMEOUT_SECONDS; if ((rc = sem_timedwait(&sem_recv, &timeout)) == -1 && errno == ETIMEDOUT) { for (int i = 0; i < 2; i++) pthread_cancel(tid[i]); } pthread_cancel(tid[TID_SEND]); test_assert(rc == 0, "timeout waiting for recv thread"); sem_destroy(&sem_recv); /* stop threads */ for (int i = 0; i < 2; i++) pthread_join(tid[i], NULL); /* verify received directory */ rc = verify_dir(sdir, ddir); test_assert(rc == 0, "directory tree verified"); free(ddir); free(sdir); err_mdex_free: mdex_free(mdex); err_free_srclist: free_srclist(srclist_head); err_free_src_dst: free(src); free(dst); return test_status; #else return test_skip(name); #endif /* HAVE_RQ_OTI */ } librecast/test/0000-0116.c000066400000000000000000000137041502456746400151370ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2023-2024 Brett Sheffield */ #define _DEFAULT_SOURCE /* be64toh */ #define _XOPEN_SOURCE 700 /* for nftw() */ #define _NETBSD_SOURCE /* required for scandir() on NetBSD */ #include "test.h" #include "testdata.h" #include "testnet.h" #include #include #include #include #include #include #include #include #include #include #if HAVE_RQ_OTI #define MAXFILESZ 1048576 #define MAXFILES 2 #define MAXDIRS 2 #define DEPTH 2 #define TIMEOUT_SECONDS 3 /* * test 0116 * * create a tree of files and directories and use lc_syncfile() to sync * the top-level directory non-recursively into the destination. * * Compare the resulting directories and ensure they match. */ static sem_t sem_recv; struct pkg_s { char *src; char *dst; }; void *thread_recv(void *arg) { struct pkg_s *pkg = (struct pkg_s *)arg; unsigned char hash[HASHSIZE]; const int flags = SYNC_SUBDIR | SYNC_ATIME | SYNC_MTIME | SYNC_OWNER | SYNC_GROUP | SYNC_MODE; ssize_t rc; mdex_aliashash(pkg->src, hash, sizeof hash); fprintf(stderr, "%s() ", __func__); hash_hex_debug(stderr, hash, sizeof hash); lc_ctx_t *lctx = lc_ctx_new(); pthread_cleanup_push((void (*)(void *))lc_ctx_free, lctx); rc = lc_syncfile(lctx, hash, pkg->dst, NULL, NULL, NULL, flags); test_assert(rc > 0, "lc_syncfile returned %zi", rc); pthread_cleanup_pop(1); /* lc_ctx_free */ sem_post(&sem_recv); return NULL; } static int scandirfilter(const struct dirent *dir) { /* filter current and parent directories */ return !(!strcmp(dir->d_name, ".") || !strcmp(dir->d_name, "..")); } /* check mode, owner, group, times */ static int statcmp(const char *src, const char *dst) { struct stat ssb, dsb; int rc; rc = stat(src, &ssb); if (!test_assert(rc == 0, "stat '%s'", src)) return -1; rc = stat(dst, &dsb); if (!test_assert(rc == 0, "stat '%s'", dst)) return -1; test_assert(ssb.st_mode == dsb.st_mode, "st_mode: '%s' %o %o", dst, ssb.st_mode, dsb.st_mode); test_assert(ssb.st_uid == dsb.st_uid, "st_uid: '%s'", dst); test_assert(ssb.st_gid == dsb.st_gid, "st_gid: '%s'", dst); test_assert(ssb.st_size == dsb.st_size, "st_size: '%s'", dst); #ifndef HAVE_UTIMENSAT /* without utimensat(), we only have microsecond precision */ ssb.st_mtim.tv_nsec /= 1000; ssb.st_mtim.tv_nsec *= 1000; ssb.st_atim.tv_nsec /= 1000; ssb.st_atim.tv_nsec *= 1000; #endif /* No point testing atime unless the filesystem is mounted noatime */ /* test_assert(ssb.st_atim.tv_nsec == dsb.st_atim.tv_nsec, "st_atim: '%s'", dst); */ test_assert(ssb.st_mtim.tv_nsec == dsb.st_mtim.tv_nsec, "st_mtim: '%s'", dst); return 0; } #endif /* HAVE_RQ_OTI */ int main(int argc, char *argv[]) { (void)argc, (void)argv; char name[] = "lc_syncfile() - sync directory (not recursive)"; #if HAVE_RQ_OTI struct dirent **namelist; lc_ctx_t *lctx; mdex_t *mdex; lc_share_t *share; pthread_t tid_recv; struct pkg_s pkg_recv = {0}; struct timespec timeout = {0}; char *src = NULL, *dst = NULL; int rc; test_cap_require(CAP_NET_ADMIN); test_name(name); test_require_net(TEST_NET_BASIC); /* create source directory tree and files */ rc = test_createtestdirs(basename(argv[0]), &src, &dst); if (!test_assert(rc == 0, "test_createtestdirs()")) return test_status; test_random_meta(src, TEST_OWN|TEST_MOD); rc = test_createtesttree(src, MAXFILESZ, MAXFILES, MAXDIRS, DEPTH, TEST_OWN|TEST_MOD); if (!test_assert(rc == 0, "test_createtesttree()")) goto err_free_src_dst; /* index source tree */ mdex = mdex_init(512); if (!test_assert(mdex != NULL, "mdex_init()")) goto err_free_src_dst; rc = mdex_addfile(mdex, src, NULL, MDEX_RECURSE); if (!test_assert(rc == 0, "mdex_addfile() returned %i", rc)) goto err_mdex_free; /* share the mdex */ lctx = lc_ctx_new(); if (!test_assert(lctx != NULL, "lc_ctx_new()")) goto err_mdex_free; share = lc_share(lctx, mdex, 0, NULL, NULL, LC_SHARE_LOOPBACK); if (!test_assert(share != NULL, "lc_share()")) goto err_free_lctx; test_assert(share != NULL, "lc_share()"); /* start receive thread, sync files */ test_log("syncing '%s' => '%s'\n", src, dst); rc = sem_init(&sem_recv, 0, 0); if (!test_assert(rc == 0, "sem_init(sem_recv)")) goto err_unshare; pkg_recv.src = src; pkg_recv.dst = dst; rc = pthread_create(&tid_recv, NULL, thread_recv, &pkg_recv); if (!test_assert(rc == 0, "create recv thread")) goto err_sem_destroy; /* handle timeout */ clock_gettime(CLOCK_REALTIME, &timeout); timeout.tv_sec += TIMEOUT_SECONDS; if ((rc = sem_timedwait(&sem_recv, &timeout)) == -1 && errno == ETIMEDOUT) { pthread_cancel(tid_recv); } test_assert(rc == 0, "timeout waiting for recv thread"); pthread_join(tid_recv, NULL); /* verify src and dst match */ /* src has no trailing slash, so the directory must be created inside dst */ struct stat ssb, dsb; char *destdir; int len; len = snprintf(NULL, 0, "%s/%s", dst, src); destdir = malloc(len + 1); if (!test_assert(destdir != NULL, "malloc destdir")) goto err_sem_destroy; if (!test_assert(len == snprintf(destdir, len + 1, "%s/%s", dst, src), "build destdir string")) goto err_free_destdir; rc = stat(destdir, &dsb); if (!test_assert(rc == 0, "%s exists", destdir)) goto err_free_destdir; rc = stat(src, &ssb); if (!test_assert(rc == 0, "stat src")) goto err_free_destdir; /* check mode, owner, group, times */ test_assert(statcmp(src, destdir) == 0, "statcmp"); /* we didn't ask for recursion, so make sure directory is empty */ rc = scandir(destdir, &namelist, scandirfilter, alphasort); test_assert(rc == 0, "destination directory exists and is empty"); err_free_destdir: free(destdir); err_sem_destroy: sem_destroy(&sem_recv); err_unshare: lc_unshare(share); err_free_lctx: lc_ctx_free(lctx); err_mdex_free: mdex_free(mdex); err_free_src_dst: free(src); free(dst); return test_status; #else return test_skip(name); #endif /* HAVE_RQ_OTI */ } librecast/test/0000-0117.c000066400000000000000000000075721502456746400151460ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2023-2024 Brett Sheffield */ #include "test.h" #include "testdata.h" #include "testnet.h" #include "testsync.h" #include #include #include #include #include #include #include #if HAVE_RQ_OTI #define MAXFILESZ 1048576 #define MAXFILES 4 #define MAXDIRS 2 #define DEPTH 2 #define TIMEOUT_SECONDS 100 /* * test 0117 * * create a tree of files and directories and use lc_syncfile() to sync * recursively to destination directory. * * Compare the resulting directories and ensure they match. */ static sem_t sem_recv; struct pkg_s { char *src; char *dst; }; void *thread_recv(void *arg) { struct pkg_s *pkg = (struct pkg_s *)arg; unsigned char hash[HASHSIZE]; const int flags = SYNC_RECURSE | SYNC_ATIME | SYNC_MTIME | SYNC_OWNER | SYNC_GROUP | SYNC_MODE; ssize_t rc; mdex_aliashash(pkg->src, hash, sizeof hash); lc_ctx_t *lctx = lc_ctx_new(); pthread_cleanup_push((void (*)(void *))lc_ctx_free, lctx); rc = lc_syncfile(lctx, hash, pkg->dst, NULL, NULL, NULL, flags); test_assert(rc > 0, "lc_syncfile returned %zi", rc); pthread_cleanup_pop(1); /* lc_ctx_free */ sem_post(&sem_recv); return NULL; } #endif /* HAVE_RQ_OTI */ int main(int argc, char *argv[]) { (void)argc, (void)argv; char name[] = "lc_syncfile() - recursive file syncing"; #if HAVE_RQ_OTI lc_ctx_t *lctx; mdex_t *mdex; lc_share_t *share; pthread_t tid_recv; struct pkg_s pkg_recv = {0}; struct timespec timeout = {0}; char *src = NULL, *dst = NULL; int rc; test_cap_require(CAP_NET_ADMIN); test_name(name); test_require_net(TEST_NET_BASIC); /* create source directory tree and files */ rc = test_createtestdirs(basename(argv[0]), &src, &dst); if (!test_assert(rc == 0, "test_createtestdirs()")) return test_status; test_random_meta(src, TEST_OWN|TEST_MOD); rc = test_createtesttree(src, MAXFILESZ, MAXFILES, MAXDIRS, DEPTH, TEST_OWN|TEST_MOD); if (!test_assert(rc == 0, "test_createtesttree()")) goto err_free_src_dst; /* index source tree */ mdex = mdex_init(512); if (!test_assert(mdex != NULL, "mdex_init()")) goto err_free_src_dst; rc = mdex_addfile(mdex, src, NULL, MDEX_RECURSE); if (!test_assert(rc == 0, "mdex_addfile() returned %i", rc)) goto err_mdex_free; #if 0 /* XXX; match src and dst match */ char cmd[128]; //snprintf(cmd, sizeof cmd, "rsync -avq %s/ %s", src, dst); snprintf(cmd, sizeof cmd, "cp -Rp %s/. %s", src, dst); test_log("`%s`\n", cmd); if (system(cmd)) { test_assert(0, "cmd failed"); goto err_free_src_dst; } #endif /* share the mdex */ lctx = lc_ctx_new(); if (!test_assert(lctx != NULL, "lc_ctx_new()")) goto err_mdex_free; share = lc_share(lctx, mdex, 0, NULL, NULL, LC_SHARE_LOOPBACK); if (!test_assert(share != NULL, "lc_share()")) goto err_free_lctx; test_assert(share != NULL, "lc_share()"); /* start receive thread, sync files */ test_log("syncing '%s' => '%s'\n", src, dst); rc = sem_init(&sem_recv, 0, 0); if (!test_assert(rc == 0, "sem_init(sem_recv)")) goto err_unshare; pkg_recv.src = src; pkg_recv.dst = dst; rc = pthread_create(&tid_recv, NULL, thread_recv, &pkg_recv); if (!test_assert(rc == 0, "create recv thread")) goto err_sem_destroy; /* handle timeout */ clock_gettime(CLOCK_REALTIME, &timeout); timeout.tv_sec += TIMEOUT_SECONDS; if ((rc = sem_timedwait(&sem_recv, &timeout)) == -1 && errno == ETIMEDOUT) { pthread_cancel(tid_recv); } test_assert(rc == 0, "timeout waiting for recv thread"); pthread_join(tid_recv, NULL); /* verify src and dst match */ test_verify_dirs(src, dst); err_sem_destroy: sem_destroy(&sem_recv); err_unshare: lc_unshare(share); err_free_lctx: lc_ctx_free(lctx); err_mdex_free: mdex_free(mdex); err_free_src_dst: free(src); free(dst); return test_status; #else return test_skip(name); #endif /* HAVE_RQ_OTI */ } librecast/test/0000-0118.c000066400000000000000000000040451502456746400151370ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2023 Brett Sheffield */ /* test 0118 * * - generate a directory tree * - calculate hash for that directory * - change a file * - recalculate hash * - hash MUST not match */ #include "test.h" #include "testdata.h" #include #include #include #include #define MAXFILESZ 1048576 #define MAXFILES 10 #define MAXDIRS 5 #define DEPTH 3 int main(int argc, char *argv[]) { (void)argc; unsigned char root1[HASHSIZE] = ""; unsigned char root2[HASHSIZE] = ""; char *src = NULL, *dst = NULL; int rc; test_name("mdex_get_directory_root()"); /* create source directory tree and files */ rc = test_createtestdirs(basename(argv[0]), &src, &dst); if (!test_assert(rc == 0, "test_createtestdirs()")) return test_status; rc = test_createtesttree(src, MAXFILESZ, MAXFILES, MAXDIRS, DEPTH, 0); if (!test_assert(rc == 0, "test_createtesttree()")) goto err_free_src_dst; /* calculate root hash of source tree */ rc = mdex_get_directory_root(src, root1); if (!test_assert(rc == 0, "mdex_get_directory_root()")) goto err_free_src_dst; /* create new (empty) file in src directory */ char newfile[] = "newfile.XXXXXX"; char owd[PATH_MAX]; if (!test_assert(getcwd(owd, sizeof owd) != NULL, "getcwd()")) goto err_free_src_dst; rc = chdir(src); if (!test_assert(rc == 0, "chdir() %s", src)) goto err_free_src_dst; rc = mkstemp(newfile); if (!test_assert(rc != -1, "mkstemp() %s", newfile)) goto err_free_src_dst; close(rc); rc = chdir(owd); if (!test_assert(rc == 0, "chdir() %s", owd)) goto err_free_src_dst; /* (re)calculate root hash of source tree */ rc = mdex_get_directory_root(src, root2); if (!test_assert(rc == 0, "mdex_get_directory_root()")) goto err_free_src_dst; /* root hashes differ */ hash_hex_debug(stderr, root1, HASHSIZE); hash_hex_debug(stderr, root2, HASHSIZE); test_assert(memcmp(root1, root2, HASHSIZE), "root hashes differ"); err_free_src_dst: free(src); free(dst); return test_status; } librecast/test/0000-0119.c000066400000000000000000000112461502456746400151410ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2023 Brett Sheffield */ /* test 0119 * * - generate a directory tree * - calculate hash for that directory * - sync src/ to dst/ * - bytes synced > 0 * - compare hashes - MUST match * - re-sync * - bytes synced == 0 * - delete a file on dst * - compare hashes - MUST not match */ #include "test.h" #include "testdata.h" #include #include #include #include #include #define MAXFILESZ 1048576 #define MAXFILES 10 #define MAXDIRS 5 #define DEPTH 3 int main(int argc, char *argv[]) { (void)argc; unsigned char root1[HASHSIZE] = ""; unsigned char root2[HASHSIZE] = ""; char *src = NULL, *dst = NULL; int flags = SYNC_RECURSE | SYNC_OWNER | SYNC_GROUP | SYNC_MODE | SYNC_ATIME | SYNC_MTIME; int rc; test_name("much ado about directory hashes (part 1)"); test_log("create source directory tree and files\n"); rc = test_createtestdirs(basename(argv[0]), &src, &dst); if (!test_assert(rc == 0, "test_createtestdirs()")) return test_status; rc = test_createtesttree(src, MAXFILESZ, MAXFILES, MAXDIRS, DEPTH, 0); if (!test_assert(rc == 0, "test_createtesttree()")) goto err_free_src_dst; test_log("calculate root hash of source tree\n"); rc = mdex_get_directory_root(src, root1); if (!test_assert(rc == 0, "mdex_get_directory_root()")) goto err_free_src_dst; test_log("calculate root hash of dst tree\n"); rc = mdex_get_directory_root(dst, root2); if (!test_assert(rc == 0, "mdex_get_directory_root()")) goto err_free_src_dst; /* root hashes differ */ hash_hex_debug(stderr, root1, HASHSIZE); hash_hex_debug(stderr, root2, HASHSIZE); test_assert(memcmp(root1, root2, HASHSIZE), "root hashes differ"); test_log("sync dst from src\n"); lc_stat_t stats = {0}; rc = lc_syncfilelocal(dst, src, NULL, &stats, NULL, flags); if (!test_assert(rc == 0, "lc_syncfilelocal() returned %i", rc)) goto err_free_src_dst; /* Ensure we did something (bytes synced > 0) */ test_assert(stats.byt_info > 0, "information bytes synced = %zu", stats.byt_info); /* (re)calculate root hash of dst tree */ rc = mdex_get_directory_root(dst, root2); if (!test_assert(rc == 0, "mdex_get_directory_root()")) goto err_free_src_dst; /* root hashes match */ hash_hex_debug(stderr, root1, HASHSIZE); hash_hex_debug(stderr, root2, HASHSIZE); test_assert(!memcmp(root1, root2, HASHSIZE), "root hashes match (1)"); test_log("(re)sync dst from src\n"); memset(&stats, 0, sizeof(stats)); rc = lc_syncfilelocal(dst, src, NULL, &stats, NULL, flags); if (!test_assert(rc == 0, "lc_syncfilelocal() returned %i", rc)) goto err_free_src_dst; /* Ensure we did nothing (bytes == 0) */ test_assert(stats.byt_info == 0, "information bytes synced = %zu", stats.byt_info); /* (re)calculate root hash of dst tree */ rc = mdex_get_directory_root(dst, root2); if (!test_assert(rc == 0, "mdex_get_directory_root()")) goto err_free_src_dst; /* root hashes (still) match */ hash_hex_debug(stderr, root1, HASHSIZE); hash_hex_debug(stderr, root2, HASHSIZE); test_assert(!memcmp(root1, root2, HASHSIZE), "root hashes match (2)"); test_log("create new (empty) file in src directory\n"); char newfile[] = "newfile.XXXXXX"; char owd[PATH_MAX]; if (!test_assert(getcwd(owd, sizeof owd) != NULL, "getcwd()")) goto err_free_src_dst; rc = chdir(src); if (!test_assert(rc == 0, "chdir() %s", src)) goto err_free_src_dst; #if 0 rc = test_data_file(newfile, 8, TEST_TMP | TEST_RND); #else rc = mkstemp(newfile); // FIXME #endif if (!test_assert(rc != -1, "mkstemp() %s", newfile)) goto err_free_src_dst; close(rc); rc = chdir(owd); if (!test_assert(rc == 0, "chdir() %s", owd)) goto err_free_src_dst; /* (re)calculate root hash of source tree */ rc = mdex_get_directory_root(src, root1); if (!test_assert(rc == 0, "mdex_get_directory_root()")) goto err_free_src_dst; /* root hashes differ */ hash_hex_debug(stderr, root1, HASHSIZE); hash_hex_debug(stderr, root2, HASHSIZE); test_assert(memcmp(root1, root2, HASHSIZE), "root hashes differ"); test_log("(re)sync dst from src\n"); memset(&stats, 0, sizeof(stats)); rc = lc_syncfilelocal(dst, src, NULL, &stats, NULL, flags); if (!test_assert(rc == 0, "lc_syncfilelocal() returned %i", rc)) goto err_free_src_dst; /* (re)calculate root hash of dst tree */ rc = mdex_get_directory_root(dst, root2); if (!test_assert(rc == 0, "mdex_get_directory_root()")) goto err_free_src_dst; /* root hashes match (again) */ hash_hex_debug(stderr, root1, HASHSIZE); hash_hex_debug(stderr, root2, HASHSIZE); test_assert(!memcmp(root1, root2, HASHSIZE), "root hashes match (3)"); err_free_src_dst: free(src); free(dst); return test_status; } librecast/test/0000-0120.c000066400000000000000000000132071502456746400151300ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2023 Brett Sheffield */ /* test 0120 * * - create src and dst directories * - create/modify files (including metadata) * - test directory hashes change when expected */ #include "test.h" #include "testdata.h" #include #include #include #include #include #include #include #include #include #define MAXFILESZ 1048576 #define MAXFILES 10 #define MAXDIRS 5 #define DEPTH 3 static int test_hash_nomatch(unsigned char *hash1, unsigned char *hash2, size_t hashlen) { hash_hex_debug(stderr, hash1, hashlen); hash_hex_debug(stderr, hash2, hashlen); return test_assert(memcmp(hash1, hash2, hashlen), "hashes MUST NOT match"); } static int test_hash_match(unsigned char *hash1, unsigned char *hash2, size_t hashlen) { hash_hex_debug(stderr, hash1, hashlen); hash_hex_debug(stderr, hash2, hashlen); return test_assert(!memcmp(hash1, hash2, hashlen), "hashes MUST match"); } static int hash_dir_nomatch(const char *dir1, const char *dir2) { unsigned char root1[HASHSIZE] = ""; unsigned char root2[HASHSIZE] = ""; int rc; test_log("calculate root hash of directories, ensure match\n"); rc = mdex_get_directory_root(dir1, root1); if (!test_assert(rc == 0, "mdex_get_directory_root() '%s'", dir1)) return -1; rc = mdex_get_directory_root(dir2, root2); if (!test_assert(rc == 0, "mdex_get_directory_root() '%s'", dir2)) return -1; return test_hash_nomatch(root1, root2, HASHSIZE); } static int hash_dir_match(const char *dir1, const char *dir2) { unsigned char root1[HASHSIZE] = ""; unsigned char root2[HASHSIZE] = ""; int rc; test_log("calculate root hash of directories, ensure match\n"); rc = mdex_get_directory_root(dir1, root1); if (!test_assert(rc == 0, "mdex_get_directory_root() '%s'", dir1)) return -1; rc = mdex_get_directory_root(dir2, root2); if (!test_assert(rc == 0, "mdex_get_directory_root() '%s'", dir2)) return -1; return test_hash_match(root1, root2, HASHSIZE); } static int mkfileat(const char *dir, const char *filename, size_t sz, const struct timeval * when) { char owd[PATH_MAX]; int rc; if (!test_assert(getcwd(owd, sizeof owd) != NULL, "getcwd()")) return -1; rc = chdir(dir); if (!test_assert(rc == 0, "chdir() %s", dir)) return -1; rc = creat(filename, 0644); if (!test_assert(rc != -1, "creat() %s", filename)) return -1; close(rc); if (sz) test_file_scratch(filename, 0, sz); if (when) utimes(filename, when); return chdir(owd); } /* cd to dir and create directory called dirname with mode */ static int mkdirin(const char *dir, const char *dirname, mode_t mode, const struct timeval * later) { char owd[PATH_MAX]; int rc; if (!test_assert(getcwd(owd, sizeof owd) != NULL, "getcwd()")) return -1; rc = chdir(dir); if (!test_assert(rc == 0, "chdir() %s", dir)) return -1; rc = mkdir(dirname, mode); if (!test_assert(rc ==0, "mkdir() %s", dirname)) return -1; if (later) utimes(dirname, later); return chdir(owd); } static int syncmtime(const char *path1, const char *path2, const char *filename) { char owd[PATH_MAX]; struct timespec t[2] = {0}; struct stat sb; int rc; if (!test_assert(getcwd(owd, sizeof owd) != NULL, "getcwd()")) return -1; rc = chdir(path1); if (!test_assert(rc == 0, "chdir() %s", path1)) return -1; if (stat(filename, &sb) == -1) return -1; rc = chdir(owd); if (!test_assert(rc == 0, "chdir() %s", owd)) return -1; rc = chdir(path2); if (!test_assert(rc == 0, "chdir() %s", path2)) return -1; t[1] = sb.st_mtim; rc = utimensat(AT_FDCWD, filename, t, AT_SYMLINK_NOFOLLOW); if (!test_assert(rc == 0, "utimensat()")) return -1; return chdir(owd); } int main(int argc, char *argv[]) { (void)argc; const char empty[] = "emptyfile"; const char dirname[] = "newdir"; char *src = NULL, *dst = NULL; struct timeval later[2]; int rc; gettimeofday(later, NULL); later[0].tv_sec++; later[1] = later[0]; test_name("much ado about directory hashes (part 2)"); test_log("create source directory tree and files\n"); rc = test_createtestdirs(basename(argv[0]), &src, &dst); if (!test_assert(rc == 0, "test_createtestdirs()")) return test_status; if (!hash_dir_match(src, dst)) goto err_free_src_dst; test_log("create new (empty) file in src directory\n"); rc = mkfileat(src, empty, 0, NULL); if (!test_assert(rc == 0, "mkfileat() %s/%s", src, empty)) goto err_free_src_dst; if (!hash_dir_nomatch(src, dst)) goto err_free_src_dst; /* create a similar file in dst directory, but with different mtime */ test_log("create new (empty) file in dst directory\n"); rc = mkfileat(dst, empty, 0, later); if (!test_assert(rc == 0, "mkfileat() %s/%s", dst, empty)) goto err_free_src_dst; test_log("hashes MUST not match, because mtime does not match\n"); if (!hash_dir_nomatch(src, dst)) goto err_free_src_dst; test_log("sync mtime, recheck\n"); if (syncmtime(src, dst, empty)) goto err_free_src_dst; if (!hash_dir_match(src, dst)) goto err_free_src_dst; test_log("create a directory in src, ensure hashes don't match\n"); if (mkdirin(src, dirname, 0755, NULL)) goto err_free_src_dst; if (!hash_dir_nomatch(src, dst)) goto err_free_src_dst; test_log("create same name directory in dst\n"); if (mkdirin(dst, dirname, 0755, later)) goto err_free_src_dst; test_log("hashes MUST not match, because mtime does not match\n"); if (!hash_dir_nomatch(src, dst)) goto err_free_src_dst; test_log("sync mtime, recheck (hashes MUST now match)\n"); if (syncmtime(src, dst, dirname)) goto err_free_src_dst; if (!hash_dir_match(src, dst)) goto err_free_src_dst; err_free_src_dst: free(src); free(dst); return test_status; } librecast/test/0000-0121.c000066400000000000000000000104021502456746400151230ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2023-2024 Brett Sheffield */ #include "test.h" #include "testdata.h" #include "testnet.h" #include "testsync.h" #include #include #include #include #include #include #include #if HAVE_RQ_OTI #define MAXFILESZ 1048576 #define MAXFILES 10 #define MAXDIRS 5 #define DEPTH 2 #define TIMEOUT_SECONDS 10 /* * test 0121 * * create a source directory with a large number of subdirectories such that * the tree does not fit in a single datagram. * Sync recursively to destination directory. * * Compare the resulting directories and ensure they match. */ static sem_t sem_recv; struct pkg_s { char *src; char *dst; }; static int create_subdirs(const char *src, size_t n) { char *dir; size_t len; int rc = 0; len = strlen(src) + 8; dir = malloc(len); if (!dir) return -1; test_log("creating %zu subdirectories\n", n); while (n--) { snprintf(dir, len, "%s/%zu", src, n); rc = mkdir(dir, 0755); if (rc != 0) break; } free(dir); return rc; } void *thread_recv(void *arg) { struct pkg_s *pkg = (struct pkg_s *)arg; unsigned char hash[HASHSIZE]; const int flags = SYNC_RECURSE | SYNC_ATIME | SYNC_MTIME | SYNC_OWNER | SYNC_GROUP | SYNC_MODE; ssize_t rc; mdex_aliashash(pkg->src, hash, sizeof hash); lc_ctx_t *lctx = lc_ctx_new(); pthread_cleanup_push((void (*)(void *))lc_ctx_free, lctx); rc = lc_syncfile(lctx, hash, pkg->dst, NULL, NULL, NULL, flags); test_assert(rc > 0, "lc_syncfile returned %zi", rc); pthread_cleanup_pop(1); /* lc_ctx_free */ sem_post(&sem_recv); return NULL; } #endif /* HAVE_RQ_OTI */ int main(int argc, char *argv[]) { (void)argc, (void)argv; char name[] = "lc_syncfile() - recursive file syncing (large directory)"; #if HAVE_RQ_OTI lc_ctx_t *lctx = NULL; mdex_t *mdex; lc_share_t *share = NULL; pthread_t tid_recv; struct pkg_s pkg_recv = {0}; struct timespec timeout = {0}; char *src = NULL, *dst = NULL; int rc; test_cap_require(CAP_NET_ADMIN); test_name(name); test_require_net(TEST_NET_BASIC); /* create src and dst directories */ rc = test_createtestdirs(basename(argv[0]), &src, &dst); if (!test_assert(rc == 0, "test_createtestdirs()")) return test_status; /* create subdirectories in src */ /* we can fit 32 x 32byte hashes in a 1024 byte payload. Create a few * more entries than that */ size_t n = 257; create_subdirs(src, n); /* index source tree */ mdex = mdex_init(512); if (!test_assert(mdex != NULL, "mdex_init()")) goto err_free_src_dst; rc = mdex_addfile(mdex, src, NULL, MDEX_RECURSE); if (!test_assert(rc == 0, "mdex_addfile() returned %i", rc)) goto err_mdex_free; #if 0 /* XXX; match src and dst match */ char cmd[128]; //snprintf(cmd, sizeof cmd, "rsync -avq %s/ %s", src, dst); snprintf(cmd, sizeof cmd, "cp -Rp %s/. %s", src, dst); test_log("`%s`\n", cmd); if (system(cmd)) { test_assert(0, "cmd failed"); goto err_free_src_dst; } #endif /* share the mdex */ lctx = lc_ctx_new(); if (!test_assert(lctx != NULL, "lc_ctx_new()")) goto err_mdex_free; share = lc_share(lctx, mdex, 0, NULL, NULL, LC_SHARE_LOOPBACK); if (!test_assert(share != NULL, "lc_share()")) goto err_free_lctx; test_assert(share != NULL, "lc_share()"); /* start receive thread, sync files */ test_log("syncing '%s' => '%s'\n", src, dst); rc = sem_init(&sem_recv, 0, 0); if (!test_assert(rc == 0, "sem_init(sem_recv)")) goto err_unshare; pkg_recv.src = src; pkg_recv.dst = dst; rc = pthread_create(&tid_recv, NULL, thread_recv, &pkg_recv); if (!test_assert(rc == 0, "create recv thread")) goto err_sem_destroy; /* handle timeout */ clock_gettime(CLOCK_REALTIME, &timeout); timeout.tv_sec += TIMEOUT_SECONDS; if ((rc = sem_timedwait(&sem_recv, &timeout)) == -1 && errno == ETIMEDOUT) { pthread_cancel(tid_recv); } test_assert(rc == 0, "timeout waiting for recv thread"); pthread_join(tid_recv, NULL); /* verify src and dst match */ test_verify_dirs(src, dst); err_sem_destroy: sem_destroy(&sem_recv); err_unshare: lc_unshare(share); err_free_lctx: lc_ctx_free(lctx); err_mdex_free: mdex_free(mdex); err_free_src_dst: free(src); free(dst); return test_status; #else return test_skip(name); #endif /* HAVE_RQ_OTI */ } librecast/test/0000-0122.c000066400000000000000000000115751502456746400151400ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2023 Brett Sheffield */ #include "test.h" #include "testdata.h" #include "testnet.h" #include "testsync.h" #include #include #include #include #include #include #include #include #define LINUX_SRC "/usr/src/linux-6.5.5" #define MAXFILESZ 1048576 #define MAXFILES 10 #define MAXDIRS 5 #define DEPTH 2 #define TIMEOUT_SECONDS 3600 /* * test 0122 * * Sync the Linux kernel using lc_syncfile() * * Compare the resulting directories and ensure they match. */ static sem_t sem_recv; struct pkg_s { char *src; char *dst; }; /* append trailing slash to string, return allocated new string */ char *appendslash(char *str) { size_t len = strlen(str); if (str[len - 1] == '/') return strdup(str); char *newstr = malloc(len + 2); assert(newstr); strcpy(newstr, str); newstr[len] = '/'; newstr[len + 1] = '\0'; return newstr; } void *thread_recv(void *arg) { struct pkg_s *pkg = (struct pkg_s *)arg; const int flags = SYNC_RECURSE | SYNC_ATIME | SYNC_MTIME | SYNC_OWNER | SYNC_GROUP | SYNC_MODE; ssize_t rc; lc_ctx_t *lctx = lc_ctx_new(); pthread_cleanup_push((void (*)(void *))lc_ctx_free, lctx); lc_ctx_stream(lctx, stderr); lc_ctx_debug(lctx, LCTX_DEBUG_SYNCFILE); char *slashed = appendslash(pkg->src); assert(slashed); pthread_cleanup_push(free, slashed); test_log("src (with trailing slash appended): '%s'\n", slashed); rc = lc_syncfile_hash(lctx, slashed, pkg->dst, NULL, NULL, NULL, flags); test_assert(rc > 0, "lc_syncfile_hash returned %zi", rc); if (rc == -1) perror("lc_syncfile_hash"); pthread_cleanup_pop(1); /* free(slashed) */ pthread_cleanup_pop(1); /* lc_ctx_free */ sem_post(&sem_recv); return NULL; } int main(int argc, char *argv[]) { (void)argc; lc_ctx_t *lctx; mdex_t *mdex; lc_share_t *share; pthread_t tid_recv; struct pkg_s pkg_recv = {0}; struct timespec timeout = {0}; char *dst = NULL; char *rpath = NULL; int rc; test_cap_require(CAP_NET_ADMIN); test_name("lc_syncfile() - recursive file syncing"); test_require_net(TEST_NET_BASIC); /* create source directory tree and files */ #if 0 char *src = NULL; rc = test_createtestdirs(basename(argv[0]), &src, &dst); if (!test_assert(rc == 0, "test_createtestdirs()")) return test_status; test_random_meta(src, TEST_OWN|TEST_MOD); rc = test_createtesttree(src, MAXFILESZ, MAXFILES, MAXDIRS, DEPTH, TEST_OWN|TEST_MOD); if (!test_assert(rc == 0, "test_createtesttree()")) goto err_free_src_dst; #else char *src = LINUX_SRC; rc = test_createtestdir(basename(argv[0]), &dst, "dst"); if (!test_assert(rc == 0, "test_createtestdir() - dst directory")) goto err_free_src_dst; #endif /* how many open files are we permitted? */ struct rlimit rlim; rc = getrlimit(RLIMIT_NOFILE, &rlim); test_log("RLIMIT_NOFILE cur = %i, max = %i\n", rlim.rlim_cur, rlim.rlim_max); /* use realpath for source */ rpath = realpath(src, NULL); /* index source tree */ mdex = mdex_init(512); if (!test_assert(mdex != NULL, "mdex_init()")) goto err_free_src_dst; mdex->stream = stderr; mdex->debug = MDEX_DEBUG_FILE; test_log("mdexing files...\n"); rc = mdex_addfile(mdex, rpath, NULL, MDEX_RECURSE); test_log("mdexing done.\n"); if (!test_assert(rc == 0, "mdex_addfile() returned %i", rc)) goto err_mdex_free; #if 0 /* XXX; match src and dst match */ char cmd[128]; //snprintf(cmd, sizeof cmd, "rsync -avq %s/ %s", src, dst); snprintf(cmd, sizeof cmd, "cp -Rp %s/. %s", src, dst); test_log("`%s`\n", cmd); if (system(cmd)) { test_assert(0, "cmd failed"); goto err_free_src_dst; } #endif /* share the mdex */ lctx = lc_ctx_new(); if (!test_assert(lctx != NULL, "lc_ctx_new()")) goto err_mdex_free; share = lc_share(lctx, mdex, 0, NULL, NULL, LC_SHARE_LOOPBACK); if (!test_assert(share != NULL, "lc_share()")) goto err_free_lctx; /* start receive thread, sync files */ rc = sem_init(&sem_recv, 0, 0); if (!test_assert(rc == 0, "sem_init(sem_recv)")) goto err_unshare; pkg_recv.src = mdex_sharepath(mdex, rpath); pkg_recv.dst = dst; test_log("syncing '%s' => '%s'\n", pkg_recv.src, pkg_recv.dst); rc = pthread_create(&tid_recv, NULL, thread_recv, &pkg_recv); if (!test_assert(rc == 0, "create recv thread")) goto err_sem_destroy; /* handle timeout */ clock_gettime(CLOCK_REALTIME, &timeout); timeout.tv_sec += TIMEOUT_SECONDS; if ((rc = sem_timedwait(&sem_recv, &timeout)) == -1 && errno == ETIMEDOUT) { pthread_cancel(tid_recv); } test_assert(rc == 0, "timeout waiting for recv thread"); pthread_join(tid_recv, NULL); /* verify src and dst match */ test_verify_dirs(rpath, dst); err_sem_destroy: sem_destroy(&sem_recv); err_unshare: lc_unshare(share); err_free_lctx: lc_ctx_free(lctx); err_mdex_free: mdex_free(mdex); err_free_src_dst: free(dst); free(pkg_recv.src); free(rpath); return test_status; } librecast/test/0000-0139.c000066400000000000000000000017361502456746400151460ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2021 Brett Sheffield */ #include "test.h" #include "testdata.h" #include #include #ifdef TEST_STRESS # define TEST_SIZE 1073741825 #else # define TEST_SIZE 209715110 #endif /* nice powers of two hide bugs */ static_assert(__builtin_popcount(TEST_SIZE) > 1, "TEST_SIZE must not be a power of 2"); int main(void) { char *data; mtree_t tree = {0}; int rc; test_name("mtree_build()"); data = malloc(TEST_SIZE); assert(data); test_random_bytes(data, TEST_SIZE); rc = mtree_init(&tree, TEST_SIZE); test_assert(rc == 0, "mtree_init()"); test_assert(tree.base >= tree.chunks, "base(%zu) > chunks(%zu)", tree.base, tree.chunks); if (rc == -1) goto exit_0; rc = mtree_build(&tree, data, NULL); test_assert(rc == 0, "mtree_build()"); #ifdef HEXDUMP mtree_hexdump(&tree, stderr); #endif mtree_free(&tree); exit_0: free(data); return test_status; } librecast/test/0000-0140.c000066400000000000000000000022251502456746400151300ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2021 Brett Sheffield */ #include "test.h" #include "testdata.h" #include #include #ifdef TEST_STRESS # define TEST_SIZE 1073741825 #else # define TEST_SIZE 209715110 #endif /* nice powers of two hide bugs */ static_assert(__builtin_popcount(TEST_SIZE) > 1, "TEST_SIZE must not be a power of 2"); int main(void) { const size_t nthreads = 16; char *data; pthread_t tid[nthreads]; q_t q = {0}; mtree_t tree = {0}; int rc; test_name("mtree_build() - preallocated job queue"); data = malloc(TEST_SIZE); assert(data); test_random_bytes(data, TEST_SIZE); /* initialize queue and threadpool */ q_init(&q); q_pool_create(tid, nthreads, q_job_seek, &q); rc = mtree_init(&tree, TEST_SIZE); test_assert(rc == 0, "mtree_init()"); if (rc == -1) goto exit_0; rc = mtree_build(&tree, data, &q); test_assert(rc == 0, "mtree_build()"); #ifdef HEXDUMP mtree_hexdump(&tree, stderr); #endif mtree_free(&tree); exit_0: /* destroy threads, free queue */ q_pool_destroy(tid, nthreads); q_free(&q); free(data); return test_status; } librecast/test/0000-0141.c000066400000000000000000000004021502456746400151240ustar00rootroot00000000000000#include "testnet.h" int main(void) { //int netlvl = 0; test_require_net(TEST_NET_BASIC); test_name("meta: test for network"); //netlvl = test_net_level(); //test_assert(netlvl == 0, "test_net_level() returned %i", netlvl); return test_status; } librecast/test/0000-0142.c000066400000000000000000000024221502456746400151310ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2023 Brett Sheffield */ /* test 0142 * NULL mtree - build an mtree of a zero-length object */ #include "test.h" #include "testdata.h" #include #include #define HEXDUMP int main(void) { unsigned char hash[HASHSIZE] = ""; unsigned char *root; char *data = NULL; mtree_t tree = {0}; int rc; test_name("mtree_build() - zero length data"); rc = mtree_init(&tree, 0); test_assert(rc == 0, "mtree_init()"); rc = mtree_build(&tree, data, NULL); test_assert(rc == 0, "mtree_build()"); #ifdef HEXDUMP mtree_hexdump(&tree, stderr); #endif rc = mtree_verify(&tree); test_assert(rc == 0, "mtree_verify()"); /* fetch root node, ensure it is all zeros */ root = mtree_nnode(&tree, 0); if (!test_assert(root != NULL, "mtree_nnode() returned root")) goto err_free_tree; test_assert(!memcmp(root, hash, HASHSIZE), "root hash is all zeros"); /* ensure max and min functions return 0 (root) */ test_assert(mtree_subtree_data_min(tree.base, 0) == 0, "mtree_subtree_data_min(base, 0) is zero"); test_assert(mtree_subtree_data_max(tree.base, 0) == 0, "mtree_subtree_data_max(base, 0) is zero"); err_free_tree: mtree_free(&tree); return test_status; } librecast/test/0000-0190.c000066400000000000000000000036511502456746400151410ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2024 Brett Sheffield */ /* test 0190 Socket OIL Filter tests */ #include "test.h" #include "testnet.h" #include #include #define CHANNELS 4 int main(void) { lc_ctx_t *lctx; lc_socket_t *sock; lc_channel_t *chan[CHANNELS]; test_name("Socket OIL Filter"); test_require_net(TEST_NET_BASIC); /* create ctx, socket and some random channels */ lctx = lc_ctx_new(); if (!test_assert(lctx != NULL, "lc_ctx_new()")) return test_status; sock = lc_socket_new(lctx); if (!test_assert(sock != NULL, "lc_socket_new()")) goto err_free_lctx; for (int i = 0; i < CHANNELS; i++) { chan[i] = lc_channel_random(lctx); if (!chan[i] || lc_channel_bind(sock, chan[i])) goto err_free_lctx; } /* join channels (except last), adding them to the OIL filter */ test_assert(sock->oil == NULL, "OIL filter is NULL"); for (int i = 0; i < CHANNELS - 1; i++) { if (!test_assert(lc_channel_join(chan[i]) == 0, "lc_channel_join()[%i]", i)) goto err_free_lctx; } test_assert(sock->oil != NULL, "OIL filter is allocated"); for (int i = 0; i < CHANNELS - 1; i++) { test_assert(lc_socket_oil_cmp(sock, chan[i]->hash) == 0, "lc_socket_oil_cmp()[%i]", i); } /* this last group was not added, ensure not found */ test_assert(lc_socket_oil_cmp(sock, chan[CHANNELS - 1]->hash) == -1, "lc_socket_oil_cmp() - check for hash not in filter"); test_assert(errno == ENOENT, "ENOENT"); /* PART channels, ensure hashes removed from OIL filter */ for (int i = 0; i < CHANNELS - 1; i++) { if (!test_assert(lc_channel_part(chan[i]) == 0, "lc_channel_part()[%i]", i)) goto err_free_lctx; errno = 0; test_assert(lc_socket_oil_cmp(sock, chan[i]->hash) == -1, "lc_socket_oil_cmp()[%i] ensure channel removed", i); test_assert(errno == ENOENT, "errno = ENOENT"); } err_free_lctx: lc_ctx_free(lctx); return test_status; } librecast/test/0000-0200.c000066400000000000000000000043251502456746400151300ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2024 Brett Sheffield */ /* * testing lc_router_new() / lc_router_free() */ #include "test.h" #include "falloc.h" #include #include int main(void) { lc_ctx_t *lctx; lc_router_t *r1, *r2; const unsigned int ports = 4; const int flags = -1; test_name("lc_router_new() / lc_router_free()"); /* first, just create and free a router and context */ lctx = lc_ctx_new(); if (!test_assert(lctx != NULL, "lc_ctx_new()")) return test_status; r1 = lc_router_new(lctx, ports, flags); if (!test_assert(r1 != NULL, "lc_router_new()")) goto err_ctx_free; test_assert(r1->ctx == lctx, "router ctx set"); test_assert(r1->ports == ports, "router ports set"); test_assert(r1->flags == flags, "router flags set"); lc_router_free(r1); lc_ctx_free(lctx); /* lc_ctx_free() should clean up router without needing explicit lc_router_free() */ lctx = lc_ctx_new(); if (!test_assert(lctx != NULL, "lc_ctx_new()")) return test_status; r1 = lc_router_new(lctx, ports, 0); if (!test_assert(r1 != NULL, "r1 allocated")) goto err_ctx_free; r2 = lc_router_new(lctx, ports, 0); if (!test_assert(r2 != NULL, "r2 allocated")) goto err_ctx_free; lc_ctx_free(lctx); /* Say bye to valgrind - it finds the things that happen next upsetting */ if (RUNNING_ON_VALGRIND) return test_status; /* force ENOMEM */ test_log("force ENOMEM\n"); lctx = lc_ctx_new(); if (!test_assert(lctx != NULL, "lc_ctx_new()")) return test_status; falloc_setfail(1); r1 = lc_router_new(lctx, ports, 0); /* will fail with ENOMEM */ test_assert(errno == ENOMEM, "lc_router_new() - ENOMEM"); test_assert(r1 == NULL, "lc_router_new() - ENOMEM, return NULL"); falloc_setfail(FALLOC_NOFAIL); lc_ctx_free(lctx); /* force ENOMEM */ test_log("force ENOMEM (router->port)\n"); lctx = lc_ctx_new(); if (!test_assert(lctx != NULL, "lc_ctx_new()")) return test_status; falloc_setfail(2); r1 = lc_router_new(lctx, ports, 0); /* will fail with ENOMEM */ test_assert(errno == ENOMEM, "lc_router_new() - ENOMEM (port)"); test_assert(r1 == NULL, "lc_router_new() - ENOMEM (port), return NULL"); err_ctx_free: lc_ctx_free(lctx); return test_status; } librecast/test/0000-0201.c000066400000000000000000000043511502456746400151300ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2024 Brett Sheffield */ /* * router port/socket tests */ #include "test.h" #include #include #define SOCKS 2 int main(void) { lc_ctx_t *lctx; lc_router_t *r1; lc_socket_t *sock[SOCKS + 1] = {0}; const unsigned int ports = 2; test_name("lc_router_socket_add() / lc_router_socket_del()"); /* create context and router */ lctx = lc_ctx_new(); if (!test_assert(lctx != NULL, "lc_ctx_new()")) return test_status; r1 = lc_router_new(lctx, ports, 0); if (!test_assert(r1 != NULL, "lc_router_new()")) goto err_ctx_free; test_assert(r1->ports == ports, "router ports set"); /* create some sockets */ for (int i = 0; i < SOCKS + 1; i++) { sock[i] = lc_socket_new(lctx); if (!sock[i]) goto err_socks_free; } /* plug sockets into router */ for (int i = 0; i < SOCKS; i++) { test_assert(lc_router_socket_add(r1, sock[i]) == 0, "lc_router_socket_add()[%i]", i); } /* check sockets are mapped to ports */ lc_socket_t **port = r1->port; for (int i = 0; i < SOCKS; i++, port++) { test_assert(*port == sock[i], "port %i connected", i); /* socket has back-reference to router */ test_assert(sock[i]->router == r1, "socket connected to router"); } /* plug extra socket into router, router will be resized * (LC_ROUTER_FLAG_FIXED not set)*/ test_assert(lc_router_socket_add(r1, sock[SOCKS]) == 0, "lc_router_socket_add() - extend router"); test_assert(r1->ports == (ports << 1), "router ports extended"); test_assert(r1->port[ports] == sock[SOCKS], "extra socket was plugged"); /* unplug socket and re-test */ int del = 1; test_assert(lc_router_socket_del(r1, sock[del]) == 0, "lc_router_socket_del()[%i]", del); test_assert(r1->port[del] == NULL, "port %i disconnected", del); test_assert(sock[del]->router == NULL, "socket connected to router"); /* try to disconnect already-disconnected socket */ errno = 0; test_assert(lc_router_socket_del(r1, sock[del]) == -1, "lc_router_socket_del()[%i]", del); test_assert(errno == ENOENT, "errno = ENOENT"); err_socks_free: for (int i = 0; i < SOCKS; i++) { if (sock[i]) lc_socket_close(sock[i]); } err_ctx_free: lc_ctx_free(lctx); return test_status; } librecast/test/0000-0202.c000066400000000000000000000032071502456746400151300ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2024 Brett Sheffield */ /* * router port/socket tests */ #include "test.h" #include #include #define SOCKS 2 int main(void) { lc_ctx_t *lctx; lc_router_t *r1; lc_socket_t *sock[SOCKS] = {0}; const unsigned int ports = 2; test_name("lc_router_socket_add() - LC_ROUTER_FLAG_FIXED"); /* create context and router */ lctx = lc_ctx_new(); if (!test_assert(lctx != NULL, "lc_ctx_new()")) return test_status; r1 = lc_router_new(lctx, ports, LC_ROUTER_FLAG_FIXED); if (!test_assert(r1 != NULL, "lc_router_new()")) goto err_ctx_free; test_assert(r1->ports == ports, "router ports set"); /* create some sockets */ for (int i = 0; i < SOCKS; i++) { sock[i] = lc_socket_new(lctx); if (!sock[i]) goto err_socks_free; } /* plug sockets into router */ for (int i = 0; i < SOCKS; i++) { test_assert(lc_router_socket_add(r1, sock[i]) == 0, "lc_router_socket_add()[%i]", i); } /* check sockets are mapped to ports */ lc_socket_t **port = r1->port; for (int i = 0; i < SOCKS; i++, port++) { test_assert(*port == sock[i], "port %i connected", i); } /* plug extra socket into router, router will NOT be resized * (LC_ROUTER_FLAG_FIXED set)*/ errno = 0; test_assert(lc_router_socket_add(r1, sock[0]) == -1, "lc_router_socket_add() - router not extended"); test_assert(errno == EMLINK, "EMLINK"); test_assert(r1->ports == ports, "router ports not extended"); err_socks_free: for (int i = 0; i < SOCKS; i++) { if (sock[i]) lc_socket_close(sock[i]); } err_ctx_free: lc_ctx_free(lctx); return test_status; } librecast/test/0000-0203.c000066400000000000000000000025141502456746400151310ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2024 Brett Sheffield */ /* * router start/stop/forwarding */ #include "test.h" #include #include #define SOCKS 4 int main(void) { lc_ctx_t *lctx; lc_router_t *r1; lc_socket_t *sock[SOCKS] = {0}; const unsigned int ports = 2; test_name("router_start() / router_stop()"); /* create context and router */ lctx = lc_ctx_new(); if (!test_assert(lctx != NULL, "lc_ctx_new()")) return test_status; r1 = lc_router_new(lctx, ports, 0); if (!test_assert(r1 != NULL, "lc_router_new()")) goto err_ctx_free; test_assert(r1->ports == ports, "router ports set"); /* create some sockets */ for (int i = 0; i < SOCKS; i++) { sock[i] = lc_socket_new(lctx); if (!sock[i]) goto err_socks_free; } /* plug sockets into router */ for (int i = 0; i < SOCKS; i++) { test_assert(lc_router_socket_add(r1, sock[i]) == 0, "lc_router_socket_add()[%i]", i); } /* start router */ if (!test_assert(lc_router_start(r1) == 0, "router_start()")) goto err_socks_free; /* stop router */ if (!test_assert(lc_router_stop(r1) == 0, "router_stop()")) goto err_socks_free; err_socks_free: for (int i = 0; i < SOCKS; i++) { if (sock[i]) lc_socket_close(sock[i]); } err_ctx_free: lc_ctx_free(lctx); return test_status; } librecast/test/0000-0204.c000066400000000000000000000020511502456746400151260ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2024 Brett Sheffield */ #include "test.h" #include #include #define ROUTERS 6 int main(void) { lc_ctx_t *lctx; lc_router_t *r[ROUTERS]; int rc; test_name("lc_router_net() - LC_TOPO_NONE"); lctx = lc_ctx_new(); if (!test_assert(lctx != NULL, "lc_ctx_new()")) return test_status; /* create some disconnected routers */ rc = lc_router_net(lctx, r, ROUTERS, LC_TOPO_NONE, 0, LC_ROUTER_FLAG_FIXED); if (!test_assert(rc == 0, "lc_router_net()")) goto err_ctx_free; for (int i = 0; i < ROUTERS; i++) { test_log("====== ROUTER %i\n", i); if (!test_assert(r[i] != NULL, "r[%i] allocated", i)) goto err_ctx_free; if (!test_assert(r[i]->ctx == lctx, "context set")) goto err_ctx_free; if (!test_assert(r[i]->flags == LC_ROUTER_FLAG_FIXED, "flags set")) goto err_ctx_free; if (!test_assert(r[i]->ports == 0, "ports == 0")) goto err_ctx_free; } err_ctx_free: lc_ctx_free(lctx); return test_status; } librecast/test/0000-0205.c000066400000000000000000000045621502456746400151400ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2024 Brett Sheffield */ #include "test.h" #include #include #define ROUTERS 7 void dump_router_links(lc_router_t *r[], int routers) { for (int i = 0; i < routers; i++) { fprintf(stderr, "r[%i] %p\n", i, (void *)r[i]); for (int p = 0; p < (int)r[i]->ports; p++) { if (r[i]->port[p]) { lc_router_t *peer = r[i]->port[p]->pair->router; fprintf(stderr, "r[%i]p[%i] %p\n", i, p, (void *)peer); } } } } int main(void) { lc_ctx_t *lctx; lc_router_t *r[ROUTERS]; const int m = ROUTERS - 1; int rc; test_name("lc_router_net() - LC_TOPO_CHAIN"); lctx = lc_ctx_new(); if (!test_assert(lctx != NULL, "lc_ctx_new()")) return test_status; /* create some daisy-chained routers */ rc = lc_router_net(lctx, r, ROUTERS, LC_TOPO_CHAIN, 0, LC_ROUTER_FLAG_FIXED); if (!test_assert(rc == 0, "lc_router_net()")) goto err_ctx_free; for (int i = 0; i < ROUTERS; i++) { test_log("====== ROUTER %i\n", i); /* check router parameters */ if (!test_assert(r[i] != NULL, "r[%i] allocated", i)) goto err_ctx_free; if (!test_assert(r[i]->ctx == lctx, "context set")) goto err_ctx_free; if (!test_assert(r[i]->flags == LC_ROUTER_FLAG_FIXED, "flags set")) goto err_ctx_free; if (!test_assert(r[i]->ports == 2, "ports == 2")) goto err_ctx_free; } dump_router_links(r, ROUTERS); /* now check ports are connected correctly */ test_assert(r[0]->port[0] == NULL, "r[0]p[0] disconnected"); for (int i = 1; i < m; i++) { int prev = (i == 0) ? m : i - 1; test_log("R%i (prev R%i)\n", i, prev); /* port 0 is connected to previous router */ if (!test_assert(r[i]->port[0] != NULL, "r[%i]p[0] connected", i)) goto err_ctx_free; test_assert(r[i]->port[0]->pair == r[prev]->port[1], "r[%i]p[1] <--> r[%i]p[0]", prev, i); if (!test_assert(r[i]->port[1] != NULL, "r[%i]p[1] connected", i)) goto err_ctx_free; } test_assert(r[m]->port[0]->pair == r[m-1]->port[1], "r[%i]p[1] <--> r[%i]p[0]", m - 1, m); if (!test_assert(r[m]->port[1] == NULL, "r[%i]p[1] disconnected", m)) goto err_ctx_free; /* bring up all ports on all routers */ for (int i = 0; i < ROUTERS; i++) lc_router_port_up(r[i], -1); test_assert(!lc_router_net_hasloop(r, ROUTERS), "routing loop not expected"); err_ctx_free: lc_ctx_free(lctx); return test_status; } librecast/test/0000-0206.c000066400000000000000000000044471502456746400151430ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2024 Brett Sheffield */ #include "test.h" #include #include #define ROUTERS 7 void dump_router_links(lc_router_t *r[], int routers) { for (int i = 0; i < routers; i++) { fprintf(stderr, "r[%i] %p\n", i, (void *)r[i]); for (int p = 0; p < (int)r[i]->ports; p++) { if (r[i]->port[p]) { lc_router_t *peer = r[i]->port[p]->pair->router; fprintf(stderr, "r[%i]p[%i] %p\n", i, p, (void *)peer); } } } } int main(void) { lc_ctx_t *lctx; lc_router_t *r[ROUTERS]; const int m = ROUTERS - 1; int rc; test_name("lc_router_net() - LC_TOPO_RING"); lctx = lc_ctx_new(); if (!test_assert(lctx != NULL, "lc_ctx_new()")) return test_status; /* create a ring of connected routers */ rc = lc_router_net(lctx, r, ROUTERS, LC_TOPO_RING, 0, LC_ROUTER_FLAG_FIXED); if (!test_assert(rc == 0, "lc_router_net()")) goto err_ctx_free; for (int i = 0; i < ROUTERS; i++) { test_log("====== ROUTER %i\n", i); /* check router parameters */ if (!test_assert(r[i] != NULL, "r[%i] allocated", i)) goto err_ctx_free; if (!test_assert(r[i]->ctx == lctx, "context set")) goto err_ctx_free; if (!test_assert(r[i]->flags == LC_ROUTER_FLAG_FIXED, "flags set")) goto err_ctx_free; if (!test_assert(r[i]->ports == 2, "ports == 2")) goto err_ctx_free; } dump_router_links(r, ROUTERS); /* now check ports are connected correctly */ for (int i = 0; i < ROUTERS; i++) { int prev = (i == 0) ? m : i - 1; test_log("R%i (prev R%i)\n", i, prev); /* port 0 is connected to previous router */ if (!test_assert(r[i]->port[0] != NULL, "r[%i]p[0] connected", i)) goto err_ctx_free; test_log("r[%i] %p\n", i, (void *)r[i]); for (int port = 0; port < (int)r[i]->ports; port++) { test_log(" p%i %p\n", port, (void *)r[i]->port[port]->pair->router); } test_assert(r[i]->port[0]->pair->router == r[prev], "r[%i]p[0] <--> r[%i]p[1]", i, prev); if (!test_assert(r[i]->port[1] != NULL, "r[%i]p[1] connected", i)) goto err_ctx_free; } /* verify that we have a routing loop */ for (int i = 0; i < ROUTERS; i++) lc_router_port_up(r[i], -1); test_assert(lc_router_net_hasloop(r, ROUTERS), "routing loop expected"); err_ctx_free: lc_ctx_free(lctx); return test_status; } librecast/test/0000-0207.c000066400000000000000000000036141502456746400151370ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2024 Brett Sheffield */ #include "test.h" #include #include #define ROUTERS 7 /* next_pow2 - Public Domain, credit to Sean Anderson from * https://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2 */ static uint32_t next_pow2(uint32_t v) { v--; v |= v >> 1; v |= v >> 2; v |= v >> 4; v |= v >> 8; v |= v >> 16; return ++v; } int main(void) { lc_ctx_t *lctx; lc_router_t *r[ROUTERS]; int rc; test_name("lc_router_net() - LC_TOPO_STAR"); lctx = lc_ctx_new(); if (!test_assert(lctx != NULL, "lc_ctx_new()")) return test_status; /* create a star topology */ rc = lc_router_net(lctx, r, ROUTERS, LC_TOPO_STAR, 0, 0); if (!test_assert(rc == 0, "lc_router_net()")) goto err_ctx_free; for (int i = 0; i < ROUTERS; i++) { test_log("====== ROUTER %i\n", i); /* check router parameters */ if (!test_assert(r[i] != NULL, "r[%i] allocated", i)) goto err_ctx_free; if (!test_assert(r[i]->ctx == lctx, "context set")) goto err_ctx_free; if (!test_assert(r[i]->flags == 0, "flags set")) goto err_ctx_free; /* r[0] has a port for each other router (round up to next power of 2), * others have 1 */ unsigned int ports = (!i) ? next_pow2(ROUTERS - 1) : 1; if (!test_assert(r[i]->ports == ports, "ports == %i", r[i]->ports)) goto err_ctx_free; } /* now check ports are connected correctly */ for (int i = 1; i < ROUTERS; i++) { int port = i - 1; if (!test_assert(r[0]->port[port] != NULL, "R[0]P[%i] connected", port)) goto err_ctx_free; test_assert(r[0]->port[port]->pair == r[i]->port[0], "R[0]P[%i] <--> R[%i][0]", port, i); } for (int i = 0; i < ROUTERS; i++) lc_router_port_up(r[i], -1); test_assert(!lc_router_net_hasloop(r, ROUTERS), "routing loop not expected"); err_ctx_free: lc_ctx_free(lctx); return test_status; } librecast/test/0000-0208.c000066400000000000000000000033751502456746400151440ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2024 Brett Sheffield */ #include "test.h" #include #include #define ROUTERS 7 int main(void) { lc_ctx_t *lctx; lc_router_t *r[ROUTERS]; int rc; test_name("lc_router_net() - LC_TOPO_MESH"); lctx = lc_ctx_new(); if (!test_assert(lctx != NULL, "lc_ctx_new()")) return test_status; /* create a full mesh of connected routers */ rc = lc_router_net(lctx, r, ROUTERS, LC_TOPO_MESH, 0, LC_ROUTER_FLAG_FIXED); if (rc) perror("lc_router_net"); if (!test_assert(rc == 0, "lc_router_net()")) goto err_ctx_free; for (int i = 0; i < ROUTERS; i++) { test_log("====== ROUTER %i\n", i); /* check router parameters */ if (!test_assert(r[i] != NULL, "r[%i] allocated", i)) goto err_ctx_free; if (!test_assert(r[i]->ctx == lctx, "context set")) goto err_ctx_free; if (!test_assert(r[i]->flags == LC_ROUTER_FLAG_FIXED, "flags set")) goto err_ctx_free; if (!test_assert(r[i]->ports == ROUTERS - 1, "ports == %i", r[i]->ports)) goto err_ctx_free; } /* now check ports are connected correctly */ for (int i = 0; i < ROUTERS; i++) { int port = i; for (int j = 0; j < ROUTERS; j++) { if (i >= j) continue; if (!test_assert(r[i]->port[port] != NULL, "R[%i]P[%i] connected", i, port)) goto err_ctx_free; test_assert(r[i]->port[port]->pair == r[j]->port[i], "R[%i]P[%i] <--> R[%i]P[%i]", i, port, j, i); port++; } } test_assert(!lc_router_net_hasloop(r, ROUTERS), "no routing loop with ports DOWN"); for (int i = 0; i < ROUTERS; i++) lc_router_port_up(r[i], -1); test_assert(lc_router_net_hasloop(r, ROUTERS), "routing loop exists with ports UP"); err_ctx_free: lc_ctx_free(lctx); return test_status; } librecast/test/0000-0209.c000066400000000000000000000101131502456746400151310ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2024 Brett Sheffield */ /* The Butterfly Network * * s0 s1 * | | * (r0) (r1) * |\ /| * | \ / | * | (r2) | * | | | * | | | * | (r3) | * | / \ | * |/ \| * (r4) (r5) * | | * s2 s3 * * r[0-5] - routers * s[0] - socket on which A is sent * s[1] - socket on which B is sent * s[2-3] - sockets on which A and B MUST be received */ #include "test.h" #include #include #define ROUTERS 6 /* total routers */ #define SOCKS 4 /* socket pairs */ int main(void) { lc_ctx_t *lctx; lc_router_t *r[ROUTERS]; lc_socket_t *sv[SOCKS * 2] = {0}; lc_socket_t *s[4]; int rc; test_name("lc_router_net() - LC_TOPO_BUTTERFLY"); lctx = lc_ctx_new(); if (!test_assert(lctx != NULL, "lc_ctx_new()")) return test_status; /* first, try failure modes */ errno = 0; rc = lc_router_net(lctx, r, 7, LC_TOPO_BUTTERFLY, 0, LC_ROUTER_FLAG_FIXED); test_assert(errno == EINVAL, "lc_router_net() errno = EINVAL when n != 6"); test_assert(rc == -1, "lc_router_net() return -1 when n != 6"); /* create a butterfly topology */ rc = lc_router_net(lctx, r, ROUTERS, LC_TOPO_BUTTERFLY, 0, LC_ROUTER_FLAG_FIXED); if (rc) perror("lc_router_net"); if (!test_assert(rc == 0, "lc_router_net()")) goto err_ctx_free; for (int i = 0; i < ROUTERS; i++) { test_log("====== ROUTER %i\n", i); /* check router parameters */ if (!test_assert(r[i] != NULL, "r[%i] allocated", i)) goto err_ctx_free; if (!test_assert(r[i]->ctx == lctx, "context set")) goto err_ctx_free; if (!test_assert(r[i]->flags == LC_ROUTER_FLAG_FIXED, "flags set")) goto err_ctx_free; if (!test_assert(r[i]->ports == 3, "ports == %i", r[i]->ports)) goto err_ctx_free; } /* create socketpairs (these aren't part of the router topology itself) */ for (int i = 0; i < SOCKS * 2; i += 2) { rc = lc_socketpair(lctx, &sv[i]); test_assert(rc == 0, "lc_socketpair()[%i]", i); } s[0] = sv[1]; s[1] = sv[3]; s[2] = sv[5]; s[3] = sv[7]; rc = lc_router_socket_add(r[0], s[0]->pair); test_assert(rc == 0, "lc_router_socket_add() R[0], S[0]"); rc = lc_router_socket_add(r[1], s[1]->pair); test_assert(rc == 0, "lc_router_socket_add() R[1], S[1]"); rc = lc_router_socket_add(r[4], s[2]->pair); test_assert(rc == 0, "lc_router_socket_add() R[4], S[2]"); rc = lc_router_socket_add(r[5], s[3]->pair); test_assert(rc == 0, "lc_router_socket_add() R[5], S[3]"); /* now check ports are connected correctly */ for (int i = 0; i < SOCKS; i++) { if (!test_assert(s[i] != NULL, "socket s[%i] allocated", i)) goto err_ctx_free; test_assert(s[i]->type == LC_SOCK_PAIR, "s[%i] is socketpair"); test_assert(s[i]->type == LC_SOCK_PAIR, "s[%i] is socketpair"); } for (int i = 0; i < ROUTERS; i++) { /* all routers have all 3 ports connected */ for (int port = 0; port < 3; port++) { if (!(test_assert(r[i]->port[port] != NULL, "R[%i]P[%i] connected", i, port))) goto err_ctx_free; } } test_assert(r[0]->port[0]->pair == r[2]->port[0], "R[0]P[0] <--> R[2]P[0]"); test_assert(r[0]->port[1]->pair == r[4]->port[0], "R[0]P[1] <--> R[4]P[0]"); test_assert(r[1]->port[0]->pair == r[2]->port[1], "R[1]P[0] <--> R[2]P[1]"); test_assert(r[1]->port[1]->pair == r[5]->port[0], "R[1]P[1] <--> R[5]P[0]"); test_assert(r[2]->port[2]->pair == r[3]->port[0], "R[2]P[2] <--> R[3]P[0]"); test_assert(r[3]->port[1]->pair == r[4]->port[1], "R[3]P[1] <--> R[4]P[1]"); test_assert(r[3]->port[2]->pair == r[5]->port[1], "R[3]P[2] <--> R[5]P[1]"); test_assert(r[0]->port[2]->pair == s[0], "R[0]P[2] <--> S[0]"); test_assert(r[1]->port[2]->pair == s[1], "R[1]P[2] <--> S[1]"); test_assert(r[4]->port[2]->pair == s[2], "R[4]P[2] <--> S[2]"); test_assert(r[5]->port[2]->pair == s[3], "R[5]P[2] <--> S[3]"); /* bring up all ports on all routers */ for (int i = 0; i < ROUTERS; i++) lc_router_port_up(r[i], -1); test_assert(lc_router_net_hasloop(r, ROUTERS), "routing loop expected"); err_ctx_free: lc_ctx_free(lctx); return test_status; } librecast/test/0000-0210.c000066400000000000000000000042701502456746400151300ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2024 Brett Sheffield */ /* create a random network topology, following a few rules: * * 1) All routers will be connected to at least one other router. * 2) All routers have a path to all other routers. * 3) Routers can be connected to another router by more than one link. * 4) Routers are not directly connected to themselves. */ #include "test.h" #include #include #define ROUTERS 7 #define PORTS ROUTERS - 1 int main(void) { lc_ctx_t *lctx; lc_router_t *r[ROUTERS]; int rc; test_name("lc_router_net() - LC_TOPO_RANDOM"); lctx = lc_ctx_new(); if (!test_assert(lctx != NULL, "lc_ctx_new()")) return test_status; /* create a random topology */ rc = lc_router_net(lctx, r, ROUTERS, LC_TOPO_RANDOM, 0, 0); if (rc) perror("lc_router_net"); if (!test_assert(rc == 0, "lc_router_net()")) goto err_ctx_free; for (int i = 0; i < ROUTERS; i++) { test_log("====== ROUTER %i\n", i); /* check router parameters */ if (!test_assert(r[i] != NULL, "r[%i] allocated", i)) goto err_ctx_free; if (!test_assert(r[i]->ctx == lctx, "context set")) goto err_ctx_free; if (!test_assert((r[i]->flags & ~LC_ROUTER_FLAG_VISIT) == 0, "flags set")) goto err_ctx_free; if (!test_assert(r[i]->ports >= PORTS, "ports == %i", r[i]->ports)) goto err_ctx_free; } for (int i = 0; i < ROUTERS; i++) { /* Rule (1) - all routers are connected to at least one other router */ int ok = 0, fail = 0; for (int port = 0; port < (int)r[i]->ports; port++) { if (r[i]->port[port]) { if (r[i]->port[port]->pair->router != r[i]) { ok++; break; } else fail++; } } test_assert(ok, "r[%i] is connected (Rule 1)", i); /* Rule (2) = all routers have a path to all other routers */ for (int j = 0; j < ROUTERS; j++) { if (i >= j) continue; test_assert(lc_router_has_path(r, ROUTERS, r[i], r[j]), "r[%i] has path to r[%i] (Rule 2)", i, j); } /* Rule (4) - routers are not directly connected to themselves */ test_assert(!fail, "r[%i] is not looped-back to itself (Rule 4)", i); } err_ctx_free: lc_ctx_free(lctx); return test_status; } librecast/test/0000-0211.c000066400000000000000000000037061502456746400151340ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2024 Brett Sheffield */ /* create a spanning tree using Primm's algorithm and random edge weights */ #include "test.h" #include #include #define ROUTERS 5 int main(void) { lc_ctx_t *lctx; lc_router_t *r[ROUTERS]; int rc; test_name("lc_router_net() - LC_TOPO_TREE"); lctx = lc_ctx_new(); if (!test_assert(lctx != NULL, "lc_ctx_new()")) return test_status; /* create a spanning tree */ rc = lc_router_net(lctx, r, ROUTERS, LC_TOPO_TREE, 0, 0); if (rc) perror("lc_router_net"); if (!test_assert(rc == 0, "lc_router_net()")) goto err_ctx_free; for (int i = 0; i < ROUTERS; i++) { test_log("====== ROUTER %i\n", i); /* check router parameters */ if (!test_assert(r[i] != NULL, "r[%i] allocated", i)) goto err_ctx_free; if (!test_assert(r[i]->ctx == lctx, "context set")) goto err_ctx_free; if (!test_assert((r[i]->flags & ~LC_ROUTER_FLAG_VISIT) == 0, "flags set")) goto err_ctx_free; if (!test_assert(r[i]->ports >= 1, "ports == %i", r[i]->ports)) goto err_ctx_free; } for (int i = 0; i < ROUTERS; i++) { /* all routers are connected to at least one other router */ int ok = 0, fail = 0; for (int port = 0; port < (int)r[i]->ports; port++) { if (r[i]->port[port]) { if (r[i]->port[port]->pair->router != r[i]) { ok++; break; } else fail++; } } test_assert(ok, "r[%i] is connected", i); /* all routers have a path to all other routers */ for (int j = 0; j < ROUTERS; j++) { if (i >= j) continue; test_assert(lc_router_has_path(r, ROUTERS, r[i], r[j]), "r[%i] has path to r[%i]", i, j); } /* routers are not directly connected to themselves */ test_assert(!fail, "r[%i] is not looped-back to itself", i); } /* ensure loop-free */ test_assert(!lc_router_net_hasloop(r, ROUTERS), "routing loop"); err_ctx_free: lc_ctx_free(lctx); return test_status; } librecast/test/0000-0212.c000066400000000000000000000172371502456746400151410ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2024 Brett Sheffield */ /* HoneyComb(n) Network * * honeycomb(0) - 3 routers in a ring * honeycomb(1) - 9 routers (honeycomb(0) inside a hexagon of 6 routers) * honeycomb(2) - 15 routers (honeycomb(1) inside a hexagon of 6 routers) * honeycomb(3) - 21 routers (honeycomb(2) inside a hexagon of 6 routers) * etc. */ #include "test.h" #include #include #define RINGS 3 /* hex rings */ #define MAX_ROUTERS 3 + 6 * RINGS /* max routers in configuration */ void dump_router_links(lc_router_t *r[], int routers) { test_log("routers: %i\n", routers); for (int i = 0; i < routers; i++) { fprintf(stderr, "r[%i] %p\n", i, (void *)r[i]); for (int p = 0; p < (int)r[i]->ports; p++) { if (r[i]->port[p]) { lc_router_t *peer = r[i]->port[p]->pair->router; fprintf(stderr, "r[%i]p[%i] %p\n", i, p, (void *)peer); } } } } /* return true if r1 connects directly to r2 */ static int router_connected(lc_router_t *r1, lc_router_t *r2) { for (int i = 0; i < (int)r1->ports; i++) { if (!r1->port[i]) continue; for (int j = 0; j < (int)r2->ports; j++) { if (!r2->port[j]) continue; if (r1->port[i]->pair == r2->port[j]) return -1; } } return 0; } static void ring_connected(lc_router_t *r[], int n) { for (int x = 0; x < n; x++) { int y = (x) ? x - 1 : n - 1; test_assert(router_connected(r[x], r[y]), "r[%i] connects to r[%i]", x, y); } } static void free_routers(lc_router_t *r[], int n) { for (int i = 0; i < n; i++) { lc_router_free(r[i]); } } int main(void) { lc_ctx_t *lctx; lc_router_t *r[MAX_ROUTERS]; int rc; test_name("lc_router_net() - LC_TOPO_HONEYCOMB"); lctx = lc_ctx_new(); if (!test_assert(lctx != NULL, "lc_ctx_new()")) return test_status; /* create a honeycomb topology */ for (int n = 2; n < 7; n++) { rc = lc_router_net(lctx, r, n, LC_TOPO_HONEYCOMB, 0, LC_ROUTER_FLAG_FIXED); if (!test_assert(rc == 0, "lc_router_net()")) { perror("lc_router_net"); goto err_ctx_free; } dump_router_links(r, n); ring_connected(r, n); free_routers(r, n); } int n = 7, x, y; rc = lc_router_net(lctx, r, n, LC_TOPO_HONEYCOMB, 0, LC_ROUTER_FLAG_FIXED); if (!test_assert(rc == 0, "lc_router_net()")) { perror("lc_router_net"); goto err_ctx_free; } dump_router_links(r, n); ring_connected(r, 6); for (int x = 6, y = 1; y <= 5; y += 2) { test_assert(router_connected(r[x], r[y]), "r[%i] connects to r[%i]", x, y); } free_routers(r, n); n = 8; rc = lc_router_net(lctx, r, n, LC_TOPO_HONEYCOMB, 0, LC_ROUTER_FLAG_FIXED); if (!test_assert(rc == 0, "lc_router_net()")) { perror("lc_router_net"); goto err_ctx_free; } dump_router_links(r, n); ring_connected(r, 6); ring_connected(&r[6], 2); x = 6, y = 1; test_assert(router_connected(r[x], r[y]), "r[%i] connects to r[%i]", x, y); y = 3; test_assert(router_connected(r[x], r[y]), "r[%i] connects to r[%i]", x, y); x = 7, y = 5; test_assert(router_connected(r[x], r[y]), "r[%i] connects to r[%i]", x, y); free_routers(r, n); n = 9; rc = lc_router_net(lctx, r, n, LC_TOPO_HONEYCOMB, 0, LC_ROUTER_FLAG_FIXED); if (!test_assert(rc == 0, "lc_router_net()")) { perror("lc_router_net"); goto err_ctx_free; } dump_router_links(r, n); ring_connected(r, 6); ring_connected(&r[6], 3); x = 6, y = 1; test_assert(router_connected(r[x], r[y]), "r[%i] connects to r[%i]", x, y); x = 8, y = 3; test_assert(router_connected(r[x], r[y]), "r[%i] connects to r[%i]", x, y); x = 7, y = 5; test_assert(router_connected(r[x], r[y]), "r[%i] connects to r[%i]", x, y); free_routers(r, n); n = 10; rc = lc_router_net(lctx, r, n, LC_TOPO_HONEYCOMB, 0, LC_ROUTER_FLAG_FIXED); if (!test_assert(rc == 0, "lc_router_net()")) { perror("lc_router_net"); goto err_ctx_free; } dump_router_links(r, n); ring_connected(r, 6); x = 6, y = 1; test_assert(router_connected(r[x], r[y]), "r[%i] connects to r[%i]", x, y); x = 8, y = 3; test_assert(router_connected(r[x], r[y]), "r[%i] connects to r[%i]", x, y); free_routers(r, n); n = 11; rc = lc_router_net(lctx, r, n, LC_TOPO_HONEYCOMB, 0, LC_ROUTER_FLAG_FIXED); if (!test_assert(rc == 0, "lc_router_net()")) { perror("lc_router_net"); goto err_ctx_free; } dump_router_links(r, n); ring_connected(r, 6); x = 6, y = 1; test_assert(router_connected(r[x], r[y]), "r[%i] connects to r[%i]", x, y); x = 8, y = 3; test_assert(router_connected(r[x], r[y]), "r[%i] connects to r[%i]", x, y); x = 10, y = 5; test_assert(router_connected(r[x], r[y]), "r[%i] connects to r[%i]", x, y); free_routers(r, n); n = 12; rc = lc_router_net(lctx, r, n, LC_TOPO_HONEYCOMB, 0, LC_ROUTER_FLAG_FIXED); if (!test_assert(rc == 0, "lc_router_net()")) { perror("lc_router_net"); goto err_ctx_free; } dump_router_links(r, n); ring_connected(r, 6); x = 6, y = 1; test_assert(router_connected(r[x], r[y]), "r[%i] connects to r[%i]", x, y); x = 8, y = 3; test_assert(router_connected(r[x], r[y]), "r[%i] connects to r[%i]", x, y); x = 10, y = 5; test_assert(router_connected(r[x], r[y]), "r[%i] connects to r[%i]", x, y); free_routers(r, n); n = 13; rc = lc_router_net(lctx, r, n, LC_TOPO_HONEYCOMB, 0, LC_ROUTER_FLAG_FIXED); if (!test_assert(rc == 0, "lc_router_net()")) { perror("lc_router_net"); goto err_ctx_free; } dump_router_links(r, n); ring_connected(r, 6); ring_connected(&r[6], 6); x = 6, y = 1; test_assert(router_connected(r[x], r[y]), "r[%i] connects to r[%i]", x, y); x = 8, y = 3; test_assert(router_connected(r[x], r[y]), "r[%i] connects to r[%i]", x, y); x = 10, y = 5; test_assert(router_connected(r[x], r[y]), "r[%i] connects to r[%i]", x, y); x = 12, y = 7; test_assert(router_connected(r[x], r[y]), "r[%i] connects to r[%i]", x, y); x = 12, y = 9; test_assert(router_connected(r[x], r[y]), "r[%i] connects to r[%i]", x, y); x = 12, y = 11; test_assert(router_connected(r[x], r[y]), "r[%i] connects to r[%i]", x, y); free_routers(r, n); n = 14; rc = lc_router_net(lctx, r, n, LC_TOPO_HONEYCOMB, 0, LC_ROUTER_FLAG_FIXED); if (!test_assert(rc == 0, "lc_router_net()")) { perror("lc_router_net"); goto err_ctx_free; } dump_router_links(r, n); ring_connected(r, 6); ring_connected(&r[6], 6); ring_connected(&r[12], 2); x = 6, y = 1; test_assert(router_connected(r[x], r[y]), "r[%i] connects to r[%i]", x, y); x = 8, y = 3; test_assert(router_connected(r[x], r[y]), "r[%i] connects to r[%i]", x, y); x = 10, y = 5; test_assert(router_connected(r[x], r[y]), "r[%i] connects to r[%i]", x, y); x = 12, y = 7; test_assert(router_connected(r[x], r[y]), "r[%i] connects to r[%i]", x, y); x = 12, y = 9; test_assert(router_connected(r[x], r[y]), "r[%i] connects to r[%i]", x, y); x = 13, y = 11; test_assert(router_connected(r[x], r[y]), "r[%i] connects to r[%i]", x, y); free_routers(r, n); n = 15; rc = lc_router_net(lctx, r, n, LC_TOPO_HONEYCOMB, 0, LC_ROUTER_FLAG_FIXED); if (!test_assert(rc == 0, "lc_router_net()")) { perror("lc_router_net"); goto err_ctx_free; } dump_router_links(r, n); ring_connected(r, 6); ring_connected(&r[6], 6); ring_connected(&r[12], 3); x = 6, y = 1; test_assert(router_connected(r[x], r[y]), "r[%i] connects to r[%i]", x, y); x = 8, y = 3; test_assert(router_connected(r[x], r[y]), "r[%i] connects to r[%i]", x, y); x = 10, y = 5; test_assert(router_connected(r[x], r[y]), "r[%i] connects to r[%i]", x, y); x = 12, y = 7; test_assert(router_connected(r[x], r[y]), "r[%i] connects to r[%i]", x, y); x = 13, y = 11; test_assert(router_connected(r[x], r[y]), "r[%i] connects to r[%i]", x, y); x = 14, y = 9; test_assert(router_connected(r[x], r[y]), "r[%i] connects to r[%i]", x, y); free_routers(r, n); err_ctx_free: lc_ctx_free(lctx); return test_status; } librecast/test/0000-0213.c000066400000000000000000000031571502456746400151360ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2024 Brett Sheffield */ #include "test.h" #include #include #define ROUTERS 15 int main(void) { lc_ctx_t *lctx; lc_router_t *r[ROUTERS]; int rc; test_name("lc_router_net_hasloop()"); lctx = lc_ctx_new(); if (!test_assert(lctx != NULL, "lc_ctx_new()")) return test_status; /* create a chain topology (no loop) */ rc = lc_router_net(lctx, r, ROUTERS, LC_TOPO_CHAIN, 0, 0); if (!test_assert(rc == 0, "lc_router_net()")) goto err_ctx_free; /* verify that we do not have a routing loop */ test_assert(!lc_router_net_hasloop(r, ROUTERS), "routing loop"); /* connect the middle node to the end to make a loop */ test_log("CONNECT R%i <--> R%i\n", ROUTERS/2, ROUTERS - 1); lc_router_connect(r[ROUTERS/2], r[ROUTERS - 1]); /* verify that we have a routing loop */ for (int i = 0; i < ROUTERS; i++) lc_router_port_up(r[i], -1); test_assert(lc_router_net_hasloop(r, ROUTERS), "routing loop expected"); lc_ctx_free(lctx); /* R0 - R1 * | * R3 - R2 * | * R4 * => a spanning tree with no loop */ lctx = lc_ctx_new(); if (!test_assert(lctx != NULL, "lc_ctx_new()")) return test_status; rc = lc_router_net(lctx, r, 5, LC_TOPO_NONE, 5, 0); if (!test_assert(rc == 0, "lc_router_net()")) goto err_ctx_free; lc_router_connect(r[0], r[1]); lc_router_connect(r[0], r[3]); lc_router_connect(r[2], r[3]); lc_router_connect(r[2], r[4]); test_assert(!lc_router_net_hasloop(r, 5), "routing loop not expected"); err_ctx_free: lc_ctx_free(lctx); return test_status; } librecast/test/0000-0214.c000066400000000000000000000102611502456746400151310ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2024 Brett Sheffield */ /* 4-port router test of port packet counters and traffic forwarding * * +--------------+ * | router (r) | * | 0 1 2 3 | ports (r->port[]) * +--------------+ * 0 2 4 6 * | | | | (sockets (s[]) * 1 3 5 7 * * There are 8 sockets (4 socketpairs) and 4 router ports. */ #include "test.h" #include #include #define PORTS 4 #define USEC 100000 static void create_socketpairs_and_connect(lc_ctx_t *lctx, lc_router_t *r, lc_socket_t *s[]) { test_log("%s()\n", __func__); int rc; for (int i = 0; i < PORTS * 2; i += 2) { rc = lc_socketpair(lctx, &s[i]); test_assert(rc == 0, "lc_socketpair()[%i]", i); rc = lc_router_socket_add(r, s[i + 1]); test_assert(rc == 0, "lc_router_socket_add()[%i]", i); } } static void check_all_ports(lc_router_t *r, int status, char msg[]) { test_log("%s()\n", __func__); for (int i = 0; i < PORTS; i++) { test_assert((r->port[i]->status & status) == status, msg, i); } } static void check_byt_and_pkt_counters(lc_router_t *r, size_t byt_in[], unsigned int pkt_in[], size_t byt_out[], unsigned int pkt_out[]) { test_log("%s()\n", __func__); for (int i = 0; i < PORTS; i++) { unsigned int pktin = aload(&r->port[i]->pkt_in); unsigned int pktout = aload(&r->port[i]->pkt_out); unsigned int bytin = aload(&r->port[i]->byt_in); unsigned int bytout = aload(&r->port[i]->byt_out); test_assert(pktin == pkt_in[i], "port[%i] pkt recv = %u/%u", i, pktin, pkt_in[i]); test_assert(bytin == byt_in[i], "port[%i] byt recv = %zu/%zu", i, bytin, byt_in[i]); test_assert(pktout == pkt_out[i], "port[%i] pkt sent = %u/%u", i, pktout, pkt_out[i]); test_assert(bytout == byt_out[i], "port[%i] byt sent = %zu/%zu", i, bytout, byt_out[i]); } } static void send_pkt_on_port(int port, lc_socket_t *s[], size_t byt_in[], unsigned int pkt_in[], size_t byt_out[], unsigned int pkt_out[], int flags) { test_log("%s() [%i]\n", __func__, port); char msg[] = "hello there"; ssize_t byt; byt = send(s[port]->sock, msg, sizeof msg, 0); if (byt > 0) { byt_in[port] += byt; pkt_in[port]++; } if ((flags & LC_PORT_FLOOD) == LC_PORT_FLOOD) { for (int i = 0; i < (int)s[1]->router->ports; i++) { if (i != port) { if (byt > 0) { byt_out[i] += byt; pkt_out[i]++; } } } } } int main(void) { lc_ctx_t *lctx; lc_router_t *r; lc_socket_t *s[PORTS * 2]; size_t byt_in[PORTS] = {0}; size_t byt_out[PORTS] = {0}; unsigned int pkt_in[PORTS] = {0}; unsigned int pkt_out[PORTS] = {0}; int rc; test_name("router port packet counters"); /* create context and router */ lctx = lc_ctx_new(); if (!test_assert(lctx != NULL, "lc_ctx_new()")) return test_status; r = lc_router_new(lctx, PORTS, LC_ROUTER_FLAG_FIXED); if (!test_assert(r != NULL, "lc_router_new() - %i-port router created", PORTS)) goto err_ctx_free; /* create socketpairs and connect to router ports */ create_socketpairs_and_connect(lctx, r, s); /* ensure packet counters are zeroed */ check_byt_and_pkt_counters(r, byt_in, pkt_in, byt_out, pkt_out); /* bring up router ports, enable forwarding and start router */ lc_router_port_up(r, -1); lc_router_port_set(r, -1, LC_PORT_FWD); check_all_ports(r, LC_PORT_UP|LC_PORT_FWD, "port[%i] status UP + FWD"); rc = lc_router_start(r); if (!test_assert(rc == 0, "lc_router_start()")) goto err_ctx_free; usleep(USEC); /* give router a moment to wake up */ /* send a packet on port 0 */ send_pkt_on_port(0, s, byt_in, pkt_in, byt_out, pkt_out, 0); usleep(USEC); /* wait for router to process packets */ check_byt_and_pkt_counters(r, byt_in, pkt_in, byt_out, pkt_out); /* turn on port flooding */ test_log("turn on port flooding (LC_PORT_FLOOD)\n"); lc_router_port_set(r, -1, LC_PORT_FLOOD); check_all_ports(r, LC_PORT_UP|LC_PORT_FWD|LC_PORT_FLOOD, "port[%i] status UP + FWD + FLOOD"); send_pkt_on_port(0, s, byt_in, pkt_in, byt_out, pkt_out, LC_PORT_FLOOD); usleep(USEC); /* wait for router to process packets */ check_byt_and_pkt_counters(r, byt_in, pkt_in, byt_out, pkt_out); err_ctx_free: lc_ctx_free(lctx); return test_status; } librecast/test/0000-0215.c000066400000000000000000000114121502456746400151310ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2024-2025 Brett Sheffield */ /* 4-port router test of traffic forwarding with OIL filter checks * * +--------------+ * | router (r) | * | 0 1 2 3 | ports (r->port[]) * +--------------+ * 0 2 4 6 * | | | | (sockets (s[]) * 1 3 5 7 * * There are 8 sockets (4 socketpairs) and 4 router ports. */ #include "test.h" #include #include #define PORTS 4 #define USEC 100000 #define OVERHEAD sizeof(lc_tlv_t) + HASHSIZE static void create_socketpairs_and_connect(lc_ctx_t *lctx, lc_router_t *r, lc_socket_t *s[]) { test_log("%s()\n", __func__); int rc; for (int i = 0; i < PORTS * 2; i += 2) { rc = lc_socketpair(lctx, &s[i]); test_assert(rc == 0, "lc_socketpair()[%i]", i); rc = lc_router_socket_add(r, s[i]); test_assert(rc == 0, "lc_router_socket_add()[%i]", i); } } static void check_all_ports(lc_router_t *r, int status, char msg[]) { test_log("%s()\n", __func__); for (int i = 0; i < PORTS; i++) { test_assert((r->port[i]->status & status) == status, msg, i); } } static void check_byt_and_pkt_counters(lc_router_t *r, size_t byt_in[], unsigned int pkt_in[], size_t byt_out[], unsigned int pkt_out[]) { test_log("%s()\n", __func__); for (int i = 0; i < PORTS; i++) { unsigned int pktin = aload(&r->port[i]->pkt_in); unsigned int pktout = aload(&r->port[i]->pkt_out); unsigned int bytin = aload(&r->port[i]->byt_in); unsigned int bytout = aload(&r->port[i]->byt_out); test_assert(pktin == pkt_in[i], "port[%i] pkt recv = %u/%u", i, pktin, pkt_in[i]); test_assert(bytin == byt_in[i], "port[%i] byt recv = %zu/%zu", i, bytin, byt_in[i]); test_assert(pktout == pkt_out[i], "port[%i] pkt sent = %u/%u", i, pktout, pkt_out[i]); test_assert(bytout == byt_out[i], "port[%i] byt sent = %zu/%zu", i, bytout, byt_out[i]); } } static ssize_t send_pkt_on_port(int port, lc_socket_t *s[], size_t byt_in[], unsigned int pkt_in[]) { test_log("%s() [%i]\n", __func__, port); lc_router_t *r = s[0]->router; lc_socket_t *sock = r->port[port]->pair; char msg[] = "hello there"; ssize_t byt; errno = 0; byt = lc_socket_send(sock, msg, sizeof msg, 0); if (byt == -1) perror("lc_socket_send()"); test_assert(byt > 0, "%zi bytes sent on port %i", byt, port); if (byt > 0) { byt_in[port] += byt + OVERHEAD; pkt_in[port]++; } return byt; } int main(void) { lc_ctx_t *lctx; lc_router_t *r; lc_socket_t *s[PORTS * 2]; lc_channel_t *chan; unsigned int pkt_in[PORTS] = {0}; unsigned int pkt_out[PORTS] = {0}; size_t byt_in[PORTS] = {0}; size_t byt_out[PORTS] = {0}; ssize_t byt; int rc; test_name("router packet forwarding (OIL filter)"); /* create context and router */ lctx = lc_ctx_new(); if (!test_assert(lctx != NULL, "lc_ctx_new()")) return test_status; r = lc_router_new(lctx, PORTS, LC_ROUTER_FLAG_FIXED); if (!test_assert(r != NULL, "lc_router_new() - %i-port router created", PORTS)) goto err_ctx_free; /* create socketpairs and connect to router ports */ create_socketpairs_and_connect(lctx, r, s); /* ensure packet counters are zeroed */ check_byt_and_pkt_counters(r, byt_in, pkt_in, byt_out, pkt_out); /* bring up router ports, enable forwarding and start router */ lc_router_port_up(r, -1); lc_router_port_set(r, -1, LC_PORT_FWD); check_all_ports(r, LC_PORT_UP|LC_PORT_FWD, "port[%i] status UP + FWD"); rc = lc_router_start(r); if (!test_assert(rc == 0, "lc_router_start()")) goto err_ctx_free; usleep(USEC); /* give router a moment to wake up */ /* create channel and bind to sock[1] */ chan = lc_channel_random(lctx); if (!(test_assert(chan != NULL, "lc_channel_random()"))) goto err_ctx_free; rc = lc_channel_bind(s[1], chan); test_assert(rc == 0, "lc_channel_bind()"); test_assert(chan->sock == s[1], "channel is bound"); /* add channel hash to OIL of socket 1 to enable sending */ rc = lc_socket_oil_add(s[1], chan->hash); test_assert(rc == 0, "lc_socket_oil_add()"); /* send a packet on port 0 */ send_pkt_on_port(0, s, byt_in, pkt_in); usleep(USEC); /* wait for router to process packets */ /* test nothing forwarded */ check_byt_and_pkt_counters(r, byt_in, pkt_in, byt_out, pkt_out); /* add channel to OIL of selected sockets */ lc_socket_oil_add(s[2], chan->hash); /* s[2] => port 1 */ lc_socket_oil_add(s[6], chan->hash); /* s[6] => port 3 */ /* test packets received on selected sockets only */ byt = send_pkt_on_port(0, s, byt_in, pkt_in); byt_out[1] += byt + OVERHEAD, pkt_out[1]++; /* port 1 subscribed */ byt_out[3] += byt + OVERHEAD, pkt_out[3]++; /* port 3 subscribed */ usleep(USEC); /* wait for router to process packets */ check_byt_and_pkt_counters(r, byt_in, pkt_in, byt_out, pkt_out); err_ctx_free: lc_ctx_free(lctx); return test_status; } librecast/test/0000-0216.c000066400000000000000000000146221502456746400151400ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2024-2025 Brett Sheffield */ /* multi-router test of traffic forwarding with OIL filter checks */ #include "test.h" #include #include #define ROUTERS 6 #define PORTS 4 #define USEC 100000 #define OVERHEAD sizeof(lc_tlv_t) + HASHSIZE struct counter_s { size_t ibyt; /* bytes in (recv) */ size_t obyt; /* bytes out (send) */ unsigned int ipkt; /* pkts in (recv) */ unsigned int opkt; /* pkts out (send) */ }; struct counter_s c[ROUTERS][PORTS]; static void print_router_port_by_addr(lc_router_t *r[], lc_socket_t *s[], void *addr) { for (int j = 0; j < ROUTERS; j++) { for (int i = 0; i < (int)r[j]->ports; i++) { if (r[j]->port[i] == addr) { test_log(" R[%i]P[%i]\n", j, i); return; } } } for (int i = 0; i < 4; i++) { if (s[i] == addr) { test_log(" S[%i]\n", i); return; } } test_log(" (nil)\n"); } static void print_port_addresses(lc_router_t *r[], lc_socket_t *s[]) { for (int j = 0; j < ROUTERS; j++) { test_log("-\n"); for (int i = 0; i < (int)r[j]->ports; i++) { test_log(" R[%i]P[%i] %p -- %p", j, i, (void *)r[j]->port[i], r[j]->port[i]->pair); print_router_port_by_addr(r, s, r[j]->port[i]->pair); } } test_log("-\n"); } static void check_byt_and_pkt_counters(lc_router_t *r[], struct counter_s c[ROUTERS][PORTS]) { for (int j = 0; j < ROUTERS; j++) { test_log("testing ports on R[%i]\n", j); for (int i = 0; i < (int)r[j]->ports; i++) { unsigned int pktin = aload(&r[j]->port[i]->pkt_in); unsigned int pktout = aload(&r[j]->port[i]->pkt_out); unsigned int bytin = aload(&r[j]->port[i]->byt_in); unsigned int bytout = aload(&r[j]->port[i]->byt_out); test_assert(pktin == c[j][i].ipkt, "r[%i]p[%i] pkt recv = %u/%u", j, i, pktin, c[j][i].ipkt); test_assert(bytin == c[j][i].ibyt, "r[%i]p[%i] byt recv = %zu/%zu", j, i, bytin, c[j][i].ibyt); test_assert(pktout == c[j][i].opkt, "r[%i]p[%i] pkt sent = %u/%u", j, i, pktout, c[j][i].opkt); test_assert(bytout == c[j][i].obyt, "r[%i]p[%i] byt sent = %zu/%zu", j, i, bytout, c[j][i].obyt); } } } static void pkt_in(int rid, int port, size_t byt) { c[rid][port].ibyt += byt + OVERHEAD; c[rid][port].ipkt++; } static void pkt_out(int rid, int port, size_t byt) { c[rid][port].obyt += byt + OVERHEAD; c[rid][port].opkt++; } static void *router_ready(void *arg) { sem_post(arg); return NULL; } int main(void) { lc_ctx_t *lctx; lc_router_t *r[ROUTERS]; lc_socket_t *sv[8] = {0}; lc_socket_t *s[4]; lc_channel_t *chan; sem_t sem_ready; char msg[] = "butterfly"; ssize_t byt; int rc; test_name("router packet forwarding (OIL filter) - multi-router"); /* create context and routers */ lctx = lc_ctx_new(); if (!test_assert(lctx != NULL, "lc_ctx_new()")) return test_status; rc = lc_router_net(lctx, r, ROUTERS, LC_TOPO_BUTTERFLY, 0, LC_ROUTER_FLAG_FIXED); if (!test_assert(rc == 0, "lc_router_net()")) goto err_ctx_free; /* create socketpairs */ for (int i = 0; i < PORTS * 2; i += 2) { rc = lc_socketpair(lctx, &sv[i]); test_assert(rc == 0, "lc_socketpair()[%i]", i); } s[0] = sv[1]; s[1] = sv[3]; s[2] = sv[5]; s[3] = sv[7]; rc = lc_router_socket_add(r[0], s[0]->pair); test_assert(rc == 0, "lc_router_socket_add() R[0], S[0]"); rc = lc_router_socket_add(r[1], s[1]->pair); test_assert(rc == 0, "lc_router_socket_add() R[1], S[1]"); rc = lc_router_socket_add(r[4], s[2]->pair); test_assert(rc == 0, "lc_router_socket_add() R[4], S[2]"); rc = lc_router_socket_add(r[5], s[3]->pair); test_assert(rc == 0, "lc_router_socket_add() R[5], S[3]"); /* verify ports connected correctly */ print_port_addresses(r, s); test_assert(r[0]->port[0]->pair == r[2]->port[0], "R[0]P[0] <--> R[2]P[0]"); test_assert(r[0]->port[1]->pair == r[4]->port[0], "R[0]P[1] <--> R[4]P[0]"); test_assert(r[1]->port[0]->pair == r[2]->port[1], "R[1]P[0] <--> R[2]P[1]"); test_assert(r[1]->port[1]->pair == r[5]->port[0], "R[1]P[1] <--> R[5]P[0]"); test_assert(r[2]->port[2]->pair == r[3]->port[0], "R[2]P[2] <--> R[3]P[0]"); test_assert(r[3]->port[1]->pair == r[4]->port[1], "R[3]P[1] <--> R[4]P[1]"); test_assert(r[3]->port[2]->pair == r[5]->port[1], "R[3]P[2] <--> R[5]P[1]"); test_assert(r[0]->port[2]->pair == s[0], "R[0]P[2] <--> S[0]"); test_assert(r[1]->port[2]->pair == s[1], "R[1]P[2] <--> S[1]"); test_assert(r[4]->port[2]->pair == s[2], "R[4]P[2] <--> S[2]"); test_assert(r[5]->port[2]->pair == s[3], "R[5]P[2] <--> S[3]"); sem_init(&sem_ready, 0, 0); /* bring up all ports on all routers and enable forwarding */ for (int i = 0; i < ROUTERS; i++) { lc_router_port_up(r[i], -1); lc_router_port_set(r[i], -1, LC_PORT_FWD); lc_router_onready(r[i], &router_ready, &sem_ready); } /* gentlemen, start your routers... */ for (int i = 0; i < ROUTERS; i++) { rc = lc_router_start(r[i]); test_assert(rc == 0, "lc_router_start()[%i]", i); } /* wait until routers ready */ for (int i = 0; i < ROUTERS; i++) { sem_wait(&sem_ready); } /* create channel and bind to sock[1] */ chan = lc_channel_random(lctx); if (!(test_assert(chan != NULL, "lc_channel_random()"))) goto err_ctx_free; rc = lc_channel_bind(s[0], chan); test_assert(rc == 0, "lc_channel_bind()"); test_assert(chan->sock == s[0], "channel is bound"); memset(c, 0, sizeof c); check_byt_and_pkt_counters(r, c); /* zeroed */ /* set OIL for various ports */ /* JOIN r[5]p[2] and propagate back to r0 */ lc_socket_oil_add(r[5]->port[2], chan->hash); lc_socket_oil_add(r[3]->port[2], chan->hash); lc_socket_oil_add(r[2]->port[2], chan->hash); lc_socket_oil_add(r[0]->port[0], chan->hash); lc_socket_oil_add(r[0]->port[2]->pair, chan->hash); /* for socket[0] */ /* JOIN r[4]p[2] and propagate back to r0 */ lc_socket_oil_add(r[4]->port[2], chan->hash); lc_socket_oil_add(r[3]->port[1], chan->hash); /* send on socket 0 */ byt = lc_socket_send(s[0], msg, sizeof msg, 0); if (!test_assert(byt > 0, "%zi bytes sent on socket[0] -> r[0]p[2]", byt)) goto err_ctx_free; /* packet flows should be: */ pkt_in(0, 2, byt); pkt_out(0, 0, byt); pkt_in(2, 0, byt); pkt_out(2, 2, byt); pkt_in(3, 0, byt); pkt_out(3, 1, byt); pkt_out(3, 2, byt); pkt_in(4, 1, byt); pkt_out(4, 2, byt); pkt_in(5, 1, byt); pkt_out(5, 2, byt); sleep(1); /* wait for routers to process packets */ sem_destroy(&sem_ready); check_byt_and_pkt_counters(r, c); err_ctx_free: lc_ctx_free(lctx); return test_status; } librecast/test/0000-0217.c000066400000000000000000000131601502456746400151350ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2024 Brett Sheffield */ /* router bandwidth test */ #include "test.h" #include #include #include #include #include #include #include #define USE_POLL 0 #define NANO 1000000000ULL #define DATALEN 512 * 1024 * 1024 /* 512 MiB */ #define PAYLOAD 1024 enum { SOCK_SEND, SOCK_RECV, }; static struct timespec start, end; static char *buf; static char *generate_source_object(size_t F) { char *obj = malloc(F); assert(obj); arc4random_buf(obj, F); test_log("source object generated (%zu bytes)\n", F); return obj; } static void print_stats(size_t bytes, struct timespec *start, struct timespec *end) { double Bs; double bps; double s = (end->tv_sec * NANO + end->tv_nsec); s -= start->tv_sec * NANO + start->tv_nsec; s /= NANO; Bs = bytes / s; bps = Bs * 8; test_log("%zu bytes sent in %lfs (%lf Gbps)\n", bytes, s, bps / 1000 / 1000 / 1000); } static void *thread_recv(void *arg) { struct iovec iov; struct msghdr msg = {0}; #if USE_POLL struct pollfd fds = {0}; int rc; #endif size_t bytes_recv = 0; ssize_t byt; int sock = *(int *)arg; msg.msg_iov = &iov; msg.msg_iovlen = 1; iov.iov_base = buf; iov.iov_len = DATALEN; #if USE_POLL fds.fd = sock; fds.events = POLLIN; #endif test_log("recving on %i\n", sock); while (bytes_recv < DATALEN) { #if USE_POLL rc = poll(&fds, 1, 10000); if (rc == -1) { perror("poll"); break; } byt = recvmsg(sock, &msg, MSG_DONTWAIT); #else byt = recvmsg(sock, &msg, 0); #endif if (byt > 0) { //test_log("read %zi bytes (tot = %zu)\n", byt, bytes_recv); bytes_recv += byt; iov.iov_base = (char *)iov.iov_base + byt; iov.iov_len -= byt; } else if (byt == -1) { perror("recvmsg"); break; } } __atomic_thread_fence(__ATOMIC_SEQ_CST); clock_gettime(CLOCK_REALTIME, &end); return NULL; } static void measure_bandwidth_memcpy(char *data, size_t len) { char *dst = malloc(len); assert(dst); test_log("memcpy\n"); clock_gettime(CLOCK_REALTIME, &start); __atomic_thread_fence(__ATOMIC_SEQ_CST); memcpy(dst, data, len); __atomic_thread_fence(__ATOMIC_SEQ_CST); clock_gettime(CLOCK_REALTIME, &end); free(dst); print_stats(len, &start, &end); } static void measure_bandwidth(char *data, size_t len, int sock_send, int sock_recv) { char *ptr; struct iovec iov; struct msghdr msg = {0}; #if USE_POLL struct pollfd fds = {0}; int rc; #endif ssize_t byt; size_t bytes_sent = 0; pthread_t tid_recv; buf = malloc(DATALEN); if (pthread_create(&tid_recv, NULL, &thread_recv, &sock_recv) == -1) { perror("pthread_create"); exit(EXIT_FAILURE); } #if USE_POLL fds.fd = sock_send; fds.events = POLLOUT; #endif msg.msg_iov = &iov; msg.msg_iovlen = 1; iov.iov_len = PAYLOAD; ptr = data; test_log("sending on %i\n", sock_send); clock_gettime(CLOCK_REALTIME, &start); __atomic_thread_fence(__ATOMIC_SEQ_CST); while (bytes_sent < len) { iov.iov_base = ptr; #if USE_POLL rc = poll(&fds, 1, 10000); if (rc == -1) { perror("poll"); break; } byt = sendmsg(sock_send, &msg, MSG_DONTWAIT); #else byt = sendmsg(sock_send, &msg, 0); #endif if (byt == -1) { if (errno == ENOBUFS) continue; perror("sendmsg"); break; } else if (byt > 0) { //test_log("send %zi bytes (tot = %zu)\n", byt, bytes_sent); ptr += byt; bytes_sent += byt; } } pthread_join(tid_recv, NULL); test_assert(memcmp(buf, data, len) == 0, "data matches"); free(buf); print_stats(bytes_sent, &start, &end); } static void *router_ready(void *arg) { test_log("%s\n", __func__); sem_post(arg); return NULL; } static void router_tests(char *data, size_t len) { /* now create a router */ lc_ctx_t *lctx; lc_router_t *r; lc_socket_t *s[4]; sem_t sem_ready; int rc; /* create context and router */ lctx = lc_ctx_new(); if (!test_assert(lctx != NULL, "lc_ctx_new()")) return; r = lc_router_new(lctx, 2, LC_ROUTER_FLAG_FIXED); if (!test_assert(r != NULL, "lc_router_new() - router created")) goto err_ctx_free; /* use one thread to preserve data ordering */ int nthreads = 1; rc = lc_ctx_qpool_init(lctx, nthreads); /* create socketpairs and connect to router */ /* socketpair (router) socketpair */ /* s[1]-s[0]-(p0[r]p1)-s[2]-s[3] */ for (int i = 0; i < 4; i += 2) { rc = lc_socketpair(lctx, &s[i]); test_assert(rc == 0, "lc_socketpair()[%i]", i); rc = lc_router_socket_add(r, s[i]); test_assert(rc == 0, "lc_router_socket_add()[%i]", i); } /* bring up router ports, enable forwarding and start router */ lc_router_port_up(r, -1); lc_router_port_set(r, -1, LC_PORT_FWD); lc_router_port_set(r, -1, LC_PORT_FLOOD); sem_init(&sem_ready, 0, 0); lc_router_onready(r, &router_ready, &sem_ready); rc = lc_router_start(r); if (!test_assert(rc == 0, "lc_router_start()")) goto err_ctx_free; sem_wait(&sem_ready); /* wait until router ready */ sem_destroy(&sem_ready); measure_bandwidth(data, len, lc_socket_raw(s[1]), lc_socket_raw(s[3])); err_ctx_free: lc_ctx_free(lctx); } int main(void) { char *data; int sv[2]; int rc; test_name("router bandwidth test"); /* generate random data */ data = generate_source_object(DATALEN); /* measure memcpy for reference */ measure_bandwidth_memcpy(data, DATALEN); /* measure bandwidth for a straight socketpair */ rc = socketpair(AF_UNIX, SOCK_DGRAM, 0, sv); test_assert(rc == 0, "socketpair()"); test_log("sockpair created %i/%i\n", sv[0], sv[1]); measure_bandwidth(data, DATALEN, sv[SOCK_SEND], sv[SOCK_RECV]); close(sv[0]); close(sv[1]); /* now run router tests */ router_tests(data, DATALEN); free(data); return test_status; } librecast/test/Makefile.in000066400000000000000000000123751502456746400160770ustar00rootroot00000000000000# SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only # Copyright (c) 2017-2024 Brett Sheffield TESTRUNNER := @TESTRUNNER@ CFLAGS := -fno-builtin-malloc -fno-builtin-calloc -I$(SOURCEDIR)/src -I$(SOURCEDIR)/include -I$(SOURCEDIR)/libs/libmld/include @CFLAGS@ CPPFLAGS := @CPPFLAGS@ FALSE := @FALSE@ TEST_SOURCES := $(wildcard ????-????.c) TEST_PROGS ?= $(TEST_SOURCES:.c=.test) TEST_MULTICAST_Linux := ip route get ff1e:: 2> /dev/null | wc -l TEST_MULTICAST_FreeBSD := case $$(route -6 get ff1e:: 2> /dev/null) in *REJECT*) echo 0;; *DONE*) echo 1;; *) echo 0 ;; esac TEST_MULTICAST_NetBSD := case $$(/sbin/route -n get -inet6 ff1e:: 2>/dev/null) in *REJECT*) echo 0;; *DONE*) echo 1;; *) echo 0 ;; esac TEST_MULTICAST_OpenBSD := case $$(route -n get -inet6 ff1e:: 2> /dev/null) in *REJECT*) echo 0;; *DONE*) echo 1;; *) echo 0 ;; esac TEST_MULTICAST_OUT = $(shell $(TEST_MULTICAST) || /bin/true) TEST_MULTICAST = $(TEST_MULTICAST_$(shell uname -s)) LDFLAGS := -L$(SOURCEDIR)/src -L$(SOURCEDIR)/libs/libmld/src -Wl,-rpath,$(SOURCEDIR)/src,-rpath,$(SOURCEDIR)/libs/libmld/src @LDFLAGS@ LDLIBS := @LIBS@ @LIBSODIUM@ @LIBLCRQ@ -llibrecast NETTOOLS := @IFCONFIG@ @IPROUTE@ OBJS := test.o testdata.o testnet.o testsync.o LASTLOG := lastlog.log LOGFILE := $(shell mktemp "testlog-XXXXXX") ANSI_RESET = "\033[0m" ANSI_BOLD := "\033[0m\033[2m" ANSI_GREEN = "\033[32m" ANSI_RED = "\033[31m" ANSI_YELLOW = "\033[33m" ANSI_WHITE = "\033[37m" PASS = $(ANSI_RESET)$(ANSI_GREEN)\ OK$(ANSI_RESET) WARN = $(ANSI_RESET)$(ANSI_YELLOW)WARN$(ANSI_RESET) FAIL = $(ANSI_RESET)$(ANSI_RED)FAIL$(ANSI_RESET) UNKN = $(ANSI_RESET)$(ANSI_WHITE)????$(ANSI_RESET) VALGRIND_LEAK_KINDS = definite,indirect,possible VALGRIND = valgrind --leak-check=full --show-leak-kinds=$(VALGRIND_LEAK_KINDS) --max-stackframe=20480160 --error-exitcode=2 --errors-for-leak-kinds=$(VALGRIND_LEAK_KINDS) --track-origins=yes define runtest = export HAVE_MULTICAST_ROUTES="$(TEST_MULTICAST_OUT)" @printf $(ANSI_BOLD) @echo -n " $(1:.test=) " @echo "================================================================================" >>$(LOGFILE) @echo "`date +"%Y-%m-%d %H:%M:%S"` test begins" >>$(LOGFILE) @echo "--------------------------------------------------------------------------------" >>$(LOGFILE) @echo -n "===> TEST $(1:.test=) " >>$(LOGFILE) @$(MEMCHECK) ./$(1) 2>>$(LOGFILE) ret=$$? @echo "--------------------------------------------------------------------------------" >>$(LOGFILE) @echo "`date +"%Y-%m-%d %H:%M:%S"` test ends" >>$(LOGFILE) @if [ $$ret -eq 0 ]; then \ printf $(PASS); echo; \ elif [ $$ret -eq 1 ]; then \ printf $(WARN); echo; \ elif [ $$ret -eq 2 ]; then \ printf $(FAIL); echo; \ fails=$$(( fails + 1 )) ; \ else \ printf $(UNKN); echo; \ fails=$$(( fails + 1 )) ; \ fi $(eval tests_run=$(shell echo $$(($(tests_run)+1)))) endef .PHONY: test clean logclean tmpclean netcheck test: $(TESTRUNNER) .PHONY: newtest newtest: $(EDITOR) `./newtest.sh` netcheck: $(NETTOOLS) ifconfig: ifconfig iproute: @echo "== LINKS ====================================================================" ip -c=never -d link show @echo "== ADDR =====================================================================" ip -c=never addr show @echo "== ROUTE ====================================================================" ip -c=never route show ip -6 -c=never route show @echo "== NEIGHBOURS ===============================================================" ip -6 -c=never neighbour @echo "== MROUTE ===================================================================" ip -6 -c=never mroute @echo "== NETNS ====================================================================" ip -6 -c=never netns @echo "=============================================================================" 0000-0000.test: 0000-0000.c $(OBJS) falloc.o $(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) -o $@ $^ $(LDLIBS) 0000-0001.test: 0000-0001.c $(OBJS) falloc.o $(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) -o $@ $^ $(LDLIBS) 0000-0002.test: 0000-0002.c $(OBJS) falloc.o $(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) -o $@ $^ $(LDLIBS) 0000-0004.test: 0000-0004.c $(OBJS) falloc.o $(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) -o $@ $^ $(LDLIBS) 0000-0200.test: 0000-0200.c $(OBJS) falloc.o $(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) -o $@ $^ $(LDLIBS) %.test: %.c $(OBJS) $(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) -o $@ $< $(OBJS) $(LDLIBS) lctest: $(TEST_PROGS) lctest -b $^ memcheck: MEMCHECK="$(VALGRIND)" $(MAKE) test memcheck/%: MEMCHECK="$(VALGRIND)" $(MAKE) test/$(@F) # if $(@F) is a directory, run tests in that directory test/%: @if [ -d "$(@F)" ]; then $(eval TEST_PROGS=$(notdir $(wildcard $(@F)/*.test))) TEST_PROGS="$(TEST_PROGS)" $(MAKE) maketest else $(eval TEST_PROGS=0000-$(@F).test) TEST_PROGS="$(TEST_PROGS)" $(MAKE) maketest fi .ONESHELL: maketest maketest: $(TEST_PROGS) @fails=0 ln -sf $(LOGFILE) $(LASTLOG) $(foreach x,$^,$(call runtest,$(x))) @echo -e "\n$(TIMESTAMP) - tests done" >> $(LOGFILE) @echo -e "$(tests_run) tests run\nlogfile: $(LOGFILE)\n" @if [ $$fails -gt 0 ]; then \ echo ", $$fails tests failed"; \ $(FALSE); else echo fi logclean: $(RM) testlog-?????? $(LASTLOG) tmpclean: $(RM) -r ????-????.src.tmp.?????? $(RM) -r ????-????.dst.tmp.?????? clean: logclean tmpclean $(RM) *.o *.test realclean: clean $(RM) Makefile librecast/test/all/000077500000000000000000000000001502456746400145725ustar00rootroot00000000000000librecast/test/all/0000-0000.test000077700000000000000000000000001502456746400204722../0000-0000.testustar00rootroot00000000000000librecast/test/all/0000-0001.test000077700000000000000000000000001502456746400204742../0000-0001.testustar00rootroot00000000000000librecast/test/all/0000-0002.test000077700000000000000000000000001502456746400204762../0000-0002.testustar00rootroot00000000000000librecast/test/all/0000-0003.test000077700000000000000000000000001502456746400205002../0000-0003.testustar00rootroot00000000000000librecast/test/all/0000-0004.test000077700000000000000000000000001502456746400205022../0000-0004.testustar00rootroot00000000000000librecast/test/all/0000-0005.test000077700000000000000000000000001502456746400205042../0000-0005.testustar00rootroot00000000000000librecast/test/all/0000-0006.test000077700000000000000000000000001502456746400205062../0000-0006.testustar00rootroot00000000000000librecast/test/all/0000-0007.test000077700000000000000000000000001502456746400205102../0000-0007.testustar00rootroot00000000000000librecast/test/all/0000-0008.test000077700000000000000000000000001502456746400205122../0000-0008.testustar00rootroot00000000000000librecast/test/all/0000-0009.test000077700000000000000000000000001502456746400205142../0000-0009.testustar00rootroot00000000000000librecast/test/all/0000-0010.test000077700000000000000000000000001502456746400204742../0000-0010.testustar00rootroot00000000000000librecast/test/all/0000-0011.test000077700000000000000000000000001502456746400204762../0000-0011.testustar00rootroot00000000000000librecast/test/all/0000-0012.test000077700000000000000000000000001502456746400205002../0000-0012.testustar00rootroot00000000000000librecast/test/all/0000-0013.test000077700000000000000000000000001502456746400205022../0000-0013.testustar00rootroot00000000000000librecast/test/all/0000-0014.test000077700000000000000000000000001502456746400205042../0000-0014.testustar00rootroot00000000000000librecast/test/all/0000-0015.test000077700000000000000000000000001502456746400205062../0000-0015.testustar00rootroot00000000000000librecast/test/all/0000-0016.test000077700000000000000000000000001502456746400205102../0000-0016.testustar00rootroot00000000000000librecast/test/all/0000-0017.test000077700000000000000000000000001502456746400205122../0000-0017.testustar00rootroot00000000000000librecast/test/all/0000-0018.test000077700000000000000000000000001502456746400205142../0000-0018.testustar00rootroot00000000000000librecast/test/all/0000-0019.test000077700000000000000000000000001502456746400205162../0000-0019.testustar00rootroot00000000000000librecast/test/all/0000-0020.test000077700000000000000000000000001502456746400204762../0000-0020.testustar00rootroot00000000000000librecast/test/all/0000-0021.test000077700000000000000000000000001502456746400205002../0000-0021.testustar00rootroot00000000000000librecast/test/all/0000-0022.test000077700000000000000000000000001502456746400205022../0000-0022.testustar00rootroot00000000000000librecast/test/all/0000-0023.test000077700000000000000000000000001502456746400205042../0000-0023.testustar00rootroot00000000000000librecast/test/all/0000-0024.test000077700000000000000000000000001502456746400205062../0000-0024.testustar00rootroot00000000000000librecast/test/all/0000-0025.test000077700000000000000000000000001502456746400205102../0000-0025.testustar00rootroot00000000000000librecast/test/all/0000-0026.test000077700000000000000000000000001502456746400205122../0000-0026.testustar00rootroot00000000000000librecast/test/all/0000-0027.test000077700000000000000000000000001502456746400205142../0000-0027.testustar00rootroot00000000000000librecast/test/all/0000-0028.test000077700000000000000000000000001502456746400205162../0000-0028.testustar00rootroot00000000000000librecast/test/all/0000-0029.test000077700000000000000000000000001502456746400205202../0000-0029.testustar00rootroot00000000000000librecast/test/all/0000-0030.test000077700000000000000000000000001502456746400205002../0000-0030.testustar00rootroot00000000000000librecast/test/all/0000-0031.test000077700000000000000000000000001502456746400205022../0000-0031.testustar00rootroot00000000000000librecast/test/all/0000-0032.test000077700000000000000000000000001502456746400205042../0000-0032.testustar00rootroot00000000000000librecast/test/all/0000-0033.test000077700000000000000000000000001502456746400205062../0000-0033.testustar00rootroot00000000000000librecast/test/all/0000-0034.test000077700000000000000000000000001502456746400205102../0000-0034.testustar00rootroot00000000000000librecast/test/all/0000-0035.test000077700000000000000000000000001502456746400205122../0000-0035.testustar00rootroot00000000000000librecast/test/all/0000-0036.test000077700000000000000000000000001502456746400205142../0000-0036.testustar00rootroot00000000000000librecast/test/all/0000-0037.test000077700000000000000000000000001502456746400205162../0000-0037.testustar00rootroot00000000000000librecast/test/all/0000-0038.test000077700000000000000000000000001502456746400205202../0000-0038.testustar00rootroot00000000000000librecast/test/all/0000-0039.test000077700000000000000000000000001502456746400205222../0000-0039.testustar00rootroot00000000000000librecast/test/all/0000-0040.test000077700000000000000000000000001502456746400205022../0000-0040.testustar00rootroot00000000000000librecast/test/all/0000-0041.test000077700000000000000000000000001502456746400205042../0000-0041.testustar00rootroot00000000000000librecast/test/all/0000-0042.test000077700000000000000000000000001502456746400205062../0000-0042.testustar00rootroot00000000000000librecast/test/all/0000-0043.test000077700000000000000000000000001502456746400205102../0000-0043.testustar00rootroot00000000000000librecast/test/all/0000-0044.test000077700000000000000000000000001502456746400205122../0000-0044.testustar00rootroot00000000000000librecast/test/all/0000-0045.test000077700000000000000000000000001502456746400205142../0000-0045.testustar00rootroot00000000000000librecast/test/all/0000-0046.test000077700000000000000000000000001502456746400205162../0000-0046.testustar00rootroot00000000000000librecast/test/all/0000-0047.test000077700000000000000000000000001502456746400205202../0000-0047.testustar00rootroot00000000000000librecast/test/all/0000-0048.test000077700000000000000000000000001502456746400205222../0000-0048.testustar00rootroot00000000000000librecast/test/all/0000-0049.test000077700000000000000000000000001502456746400205242../0000-0049.testustar00rootroot00000000000000librecast/test/all/0000-0050.test000077700000000000000000000000001502456746400205042../0000-0050.testustar00rootroot00000000000000librecast/test/all/0000-0051.test000077700000000000000000000000001502456746400205062../0000-0051.testustar00rootroot00000000000000librecast/test/all/0000-0052.test000077700000000000000000000000001502456746400205102../0000-0052.testustar00rootroot00000000000000librecast/test/all/0000-0053.test000077700000000000000000000000001502456746400205122../0000-0053.testustar00rootroot00000000000000librecast/test/all/0000-0054.test000077700000000000000000000000001502456746400205142../0000-0054.testustar00rootroot00000000000000librecast/test/all/0000-0055.test000077700000000000000000000000001502456746400205162../0000-0055.testustar00rootroot00000000000000librecast/test/all/0000-0056.test000077700000000000000000000000001502456746400205202../0000-0056.testustar00rootroot00000000000000librecast/test/all/0000-0057.test000077700000000000000000000000001502456746400205222../0000-0057.testustar00rootroot00000000000000librecast/test/all/0000-0058.test000077700000000000000000000000001502456746400205242../0000-0058.testustar00rootroot00000000000000librecast/test/all/0000-0059.test000077700000000000000000000000001502456746400205262../0000-0059.testustar00rootroot00000000000000librecast/test/all/0000-0060.test000077700000000000000000000000001502456746400220172test/enc/0000-0060.testustar00rootroot00000000000000librecast/test/all/0000-0061.test000077700000000000000000000000001502456746400205102../0000-0061.testustar00rootroot00000000000000librecast/test/all/0000-0063.test000077700000000000000000000000001502456746400205142../0000-0063.testustar00rootroot00000000000000librecast/test/all/0000-0064.test000077700000000000000000000000001502456746400205162../0000-0064.testustar00rootroot00000000000000librecast/test/all/0000-0066.test000077700000000000000000000000001502456746400205222../0000-0066.testustar00rootroot00000000000000librecast/test/all/0000-0069.test000077700000000000000000000000001502456746400205302../0000-0069.testustar00rootroot00000000000000librecast/test/all/0000-0070.test000077700000000000000000000000001502456746400205102../0000-0070.testustar00rootroot00000000000000librecast/test/all/0000-0071.test000077700000000000000000000000001502456746400205122../0000-0071.testustar00rootroot00000000000000librecast/test/all/0000-0072.test000077700000000000000000000000001502456746400205142../0000-0072.testustar00rootroot00000000000000librecast/test/all/0000-0073.test000077700000000000000000000000001502456746400205162../0000-0073.testustar00rootroot00000000000000librecast/test/all/0000-0074.test000077700000000000000000000000001502456746400205202../0000-0074.testustar00rootroot00000000000000librecast/test/all/0000-0075.test000077700000000000000000000000001502456746400205222../0000-0075.testustar00rootroot00000000000000librecast/test/all/0000-0076.test000077700000000000000000000000001502456746400205242../0000-0076.testustar00rootroot00000000000000librecast/test/all/0000-0077.test000077700000000000000000000000001502456746400205262../0000-0077.testustar00rootroot00000000000000librecast/test/all/0000-0078.test000077700000000000000000000000001502456746400205302../0000-0078.testustar00rootroot00000000000000librecast/test/all/0000-0079.test000077700000000000000000000000001502456746400205322../0000-0079.testustar00rootroot00000000000000librecast/test/all/0000-0082.test000077700000000000000000000000001502456746400205162../0000-0082.testustar00rootroot00000000000000librecast/test/all/0000-0083.test000077700000000000000000000000001502456746400205202../0000-0083.testustar00rootroot00000000000000librecast/test/all/0000-0084.test000077700000000000000000000000001502456746400205222../0000-0084.testustar00rootroot00000000000000librecast/test/all/0000-0088.test000077700000000000000000000000001502456746400205322../0000-0088.testustar00rootroot00000000000000librecast/test/all/0000-0090.test000077700000000000000000000000001502456746400205142../0000-0090.testustar00rootroot00000000000000librecast/test/all/0000-0091.test000077700000000000000000000000001502456746400205162../0000-0091.testustar00rootroot00000000000000librecast/test/all/0000-0092.test000077700000000000000000000000001502456746400205202../0000-0092.testustar00rootroot00000000000000librecast/test/all/0000-0093.test000077700000000000000000000000001502456746400205222../0000-0093.testustar00rootroot00000000000000librecast/test/all/0000-0100.test000077700000000000000000000000001502456746400204742../0000-0100.testustar00rootroot00000000000000librecast/test/all/0000-0101.test000077700000000000000000000000001502456746400204762../0000-0101.testustar00rootroot00000000000000librecast/test/all/0000-0110.test000077700000000000000000000000001502456746400204762../0000-0110.testustar00rootroot00000000000000librecast/test/all/0000-0111.test000077700000000000000000000000001502456746400205002../0000-0111.testustar00rootroot00000000000000librecast/test/all/0000-0112.test000077700000000000000000000000001502456746400205022../0000-0112.testustar00rootroot00000000000000librecast/test/all/0000-0113.test000077700000000000000000000000001502456746400205042../0000-0113.testustar00rootroot00000000000000librecast/test/all/0000-0114.test000077700000000000000000000000001502456746400205062../0000-0114.testustar00rootroot00000000000000librecast/test/all/0000-0115.test000077700000000000000000000000001502456746400205102../0000-0115.testustar00rootroot00000000000000librecast/test/all/0000-0116.test000077700000000000000000000000001502456746400205122../0000-0116.testustar00rootroot00000000000000librecast/test/all/0000-0117.test000077700000000000000000000000001502456746400205142../0000-0117.testustar00rootroot00000000000000librecast/test/all/0000-0118.test000077700000000000000000000000001502456746400205162../0000-0118.testustar00rootroot00000000000000librecast/test/all/0000-0119.test000077700000000000000000000000001502456746400205202../0000-0119.testustar00rootroot00000000000000librecast/test/all/0000-0120.test000077700000000000000000000000001502456746400205002../0000-0120.testustar00rootroot00000000000000librecast/test/all/0000-0121.test000077700000000000000000000000001502456746400205022../0000-0121.testustar00rootroot00000000000000librecast/test/all/0000-0139.test000077700000000000000000000000001502456746400205242../0000-0139.testustar00rootroot00000000000000librecast/test/all/0000-0140.test000077700000000000000000000000001502456746400205042../0000-0140.testustar00rootroot00000000000000librecast/test/all/0000-0142.test000077700000000000000000000000001502456746400205102../0000-0142.testustar00rootroot00000000000000librecast/test/all/0000-0190.test000077700000000000000000000000001502456746400205162../0000-0190.testustar00rootroot00000000000000librecast/test/all/0000-0200.test000077700000000000000000000000001502456746400204762../0000-0200.testustar00rootroot00000000000000librecast/test/all/0000-0201.test000077700000000000000000000000001502456746400205002../0000-0201.testustar00rootroot00000000000000librecast/test/all/0000-0202.test000077700000000000000000000000001502456746400205022../0000-0202.testustar00rootroot00000000000000librecast/test/all/0000-0203.test000077700000000000000000000000001502456746400205042../0000-0203.testustar00rootroot00000000000000librecast/test/all/0000-0204.test000077700000000000000000000000001502456746400205062../0000-0204.testustar00rootroot00000000000000librecast/test/all/0000-0205.test000077700000000000000000000000001502456746400205102../0000-0205.testustar00rootroot00000000000000librecast/test/all/0000-0206.test000077700000000000000000000000001502456746400205122../0000-0206.testustar00rootroot00000000000000librecast/test/all/0000-0207.test000077700000000000000000000000001502456746400205142../0000-0207.testustar00rootroot00000000000000librecast/test/all/0000-0208.test000077700000000000000000000000001502456746400205162../0000-0208.testustar00rootroot00000000000000librecast/test/all/0000-0209.test000077700000000000000000000000001502456746400205202../0000-0209.testustar00rootroot00000000000000librecast/test/all/0000-0210.test000077700000000000000000000000001502456746400205002../0000-0210.testustar00rootroot00000000000000librecast/test/all/0000-0211.test000077700000000000000000000000001502456746400205022../0000-0211.testustar00rootroot00000000000000librecast/test/all/0000-0212.test000077700000000000000000000000001502456746400205042../0000-0212.testustar00rootroot00000000000000librecast/test/all/0000-0213.test000077700000000000000000000000001502456746400205062../0000-0213.testustar00rootroot00000000000000librecast/test/all/0000-0214.test000077700000000000000000000000001502456746400205102../0000-0214.testustar00rootroot00000000000000librecast/test/all/0000-0215.test000077700000000000000000000000001502456746400205122../0000-0215.testustar00rootroot00000000000000librecast/test/all/0000-0216.test000077700000000000000000000000001502456746400205142../0000-0216.testustar00rootroot00000000000000librecast/test/enc/000077500000000000000000000000001502456746400145675ustar00rootroot00000000000000librecast/test/enc/0000-0007.test000077700000000000000000000000001502456746400205052../0000-0007.testustar00rootroot00000000000000librecast/test/enc/0000-0008.test000077700000000000000000000000001502456746400205072../0000-0008.testustar00rootroot00000000000000librecast/test/enc/0000-0036.test000077700000000000000000000000001502456746400205112../0000-0036.testustar00rootroot00000000000000librecast/test/enc/0000-0037.test000077700000000000000000000000001502456746400205132../0000-0037.testustar00rootroot00000000000000librecast/test/enc/0000-0038.test000077700000000000000000000000001502456746400205152../0000-0038.testustar00rootroot00000000000000librecast/test/enc/0000-0040.test000077700000000000000000000000001502456746400204772../0000-0040.testustar00rootroot00000000000000librecast/test/enc/0000-0041.test000077700000000000000000000000001502456746400205012../0000-0041.testustar00rootroot00000000000000librecast/test/enc/0000-0057.test000077700000000000000000000000001502456746400205172../0000-0057.testustar00rootroot00000000000000librecast/test/enc/0000-0058.test000077700000000000000000000000001502456746400205212../0000-0058.testustar00rootroot00000000000000librecast/test/enc/0000-0059.test000077700000000000000000000000001502456746400205232../0000-0059.testustar00rootroot00000000000000librecast/test/enc/0000-0079.test000077700000000000000000000000001502456746400205272../0000-0079.testustar00rootroot00000000000000librecast/test/enc/0000-0083.test000077700000000000000000000000001502456746400205152../0000-0083.testustar00rootroot00000000000000librecast/test/enc/0000-0093.test000077700000000000000000000000001502456746400205172../0000-0093.testustar00rootroot00000000000000librecast/test/falloc.c000066400000000000000000000027641502456746400154370ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2021-2022 Brett Sheffield */ #define _GNU_SOURCE #include #include #include #include #include static volatile int allock; static size_t stackptr; static char stackbuf[1024]; static void *(*_malloc)(size_t); static void (*_free)(void *); static int falloc_fail = -1; /* *alloc fails when zero - decremented each allocation */ static void *falloc_enomem(void) { fprintf(stderr, "falloc forcing ENOMEM\n"); errno = ENOMEM; return NULL; } void *malloc(size_t size) { if (allock) { /* thanks to FatalFlaw for the idea * https://stackoverflow.com/questions/6083337/overriding-malloc-using-the-ld-preload-mechanism */ /* dlsym calls calloc() - hand it a block from our stack */ void *p; p = stackbuf + stackptr; stackptr += size; return p; } else if (!_malloc) { allock = 1; *(void **)&_malloc = dlsym(RTLD_NEXT, "malloc"); *(void **)&_free = dlsym(RTLD_NEXT, "free"); allock = 0; } if (falloc_fail > 0) falloc_fail--; if (!falloc_fail) return falloc_enomem(); return _malloc(size); } void *calloc(size_t nmemb, size_t size) { void *ptr; size_t sz = nmemb * size; ptr = malloc(sz); if (!ptr) return NULL; memset(ptr, 0, sz); return ptr; } void free(void *ptr) { if (!ptr) return; if ((char *)ptr < stackbuf || (char *)ptr > stackbuf + sizeof stackbuf) _free(ptr); } void falloc_setfail(int failafter) { falloc_fail = failafter; } librecast/test/falloc.h000066400000000000000000000010241502456746400154300ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2021,2023 Brett Sheffield */ #define FALLOC_NOFAIL -1 /* wrappers for *alloc */ __attribute__((malloc)) __attribute__((alloc_size(1,2))) void *calloc(size_t nmemb, size_t size); __attribute__((malloc)) __attribute__((alloc_size(1))) void *malloc(size_t size); /* set *alloc calls to force failure with ENOMEM after failafter allocations. * Set failafter to -1 to never force fail (default) */ void falloc_setfail(int failafter); librecast/test/mdex/000077500000000000000000000000001502456746400147575ustar00rootroot00000000000000librecast/test/mdex/0000-0046.test000077700000000000000000000000001502456746400207032../0000-0046.testustar00rootroot00000000000000librecast/test/mdex/0000-0047.test000077700000000000000000000000001502456746400207052../0000-0047.testustar00rootroot00000000000000librecast/test/mdex/0000-0049.test000077700000000000000000000000001502456746400207112../0000-0049.testustar00rootroot00000000000000librecast/test/mdex/0000-0050.test000077700000000000000000000000001502456746400206712../0000-0050.testustar00rootroot00000000000000librecast/test/mdex/0000-0051.test000077700000000000000000000000001502456746400206732../0000-0051.testustar00rootroot00000000000000librecast/test/mdex/0000-0052.test000077700000000000000000000000001502456746400206752../0000-0052.testustar00rootroot00000000000000librecast/test/mdex/0000-0053.test000077700000000000000000000000001502456746400206772../0000-0053.testustar00rootroot00000000000000librecast/test/mdex/0000-0054.test000077700000000000000000000000001502456746400207012../0000-0054.testustar00rootroot00000000000000librecast/test/mdex/0000-0061.test000077700000000000000000000000001502456746400206752../0000-0061.testustar00rootroot00000000000000librecast/test/mdex/0000-0064.test000077700000000000000000000000001502456746400207032../0000-0064.testustar00rootroot00000000000000librecast/test/mdex/0000-0113.test000077700000000000000000000000001502456746400206712../0000-0113.testustar00rootroot00000000000000librecast/test/mdex/0000-0118.test000077700000000000000000000000001502456746400207032../0000-0118.testustar00rootroot00000000000000librecast/test/mdex/0000-0119.test000077700000000000000000000000001502456746400207052../0000-0119.testustar00rootroot00000000000000librecast/test/mdex/0000-0120.test000077700000000000000000000000001502456746400206652../0000-0120.testustar00rootroot00000000000000librecast/test/mtree/000077500000000000000000000000001502456746400151365ustar00rootroot00000000000000librecast/test/mtree/0000-0139.test000077700000000000000000000000001502456746400210702../0000-0139.testustar00rootroot00000000000000librecast/test/mtree/0000-0140.test000077700000000000000000000000001502456746400210502../0000-0140.testustar00rootroot00000000000000librecast/test/mtree/0000-0142.test000077700000000000000000000000001502456746400210542../0000-0142.testustar00rootroot00000000000000librecast/test/newtest.sh000077500000000000000000000006731502456746400160600ustar00rootroot00000000000000#!/bin/sh -ue SKEL="skel.c" # first, find filename for new test for i in `seq -w 0 9999` do TESTEXEC="0000-$i.test" TESTFILE="0000-$i.c" if [ ! -f ${TESTFILE} ]; then break fi done head -n1 ${SKEL} > ${TESTFILE} echo "/* Copyright (c) `date +"%Y"` `git config --get user.name` <`git config --get user.email`> */" >> ${TESTFILE} tail -n+3 ${SKEL} >> ${TESTFILE} if [ -d all ]; then cd all ln -s ../${TESTEXEC} fi echo ${TESTFILE} librecast/test/readlock/000077500000000000000000000000001502456746400156065ustar00rootroot00000000000000librecast/test/readlock/0000-0066.test000077700000000000000000000000001502456746400215362../0000-0066.testustar00rootroot00000000000000librecast/test/readlock/0000-0067.test000077700000000000000000000000001502456746400215402../0000-0067.testustar00rootroot00000000000000librecast/test/readlock/0000-0068.test000077700000000000000000000000001502456746400215422../0000-0068.testustar00rootroot00000000000000librecast/test/router/000077500000000000000000000000001502456746400153425ustar00rootroot00000000000000librecast/test/router/0000-0200.test000077700000000000000000000000001502456746400212462../0000-0200.testustar00rootroot00000000000000librecast/test/router/0000-0201.test000077700000000000000000000000001502456746400212502../0000-0201.testustar00rootroot00000000000000librecast/test/router/0000-0202.test000077700000000000000000000000001502456746400212522../0000-0202.testustar00rootroot00000000000000librecast/test/router/0000-0203.test000077700000000000000000000000001502456746400212542../0000-0203.testustar00rootroot00000000000000librecast/test/router/0000-0204.test000077700000000000000000000000001502456746400212562../0000-0204.testustar00rootroot00000000000000librecast/test/router/0000-0205.test000077700000000000000000000000001502456746400212602../0000-0205.testustar00rootroot00000000000000librecast/test/router/0000-0206.test000077700000000000000000000000001502456746400212622../0000-0206.testustar00rootroot00000000000000librecast/test/router/0000-0207.test000077700000000000000000000000001502456746400212642../0000-0207.testustar00rootroot00000000000000librecast/test/router/0000-0208.test000077700000000000000000000000001502456746400212662../0000-0208.testustar00rootroot00000000000000librecast/test/router/0000-0209.test000077700000000000000000000000001502456746400212702../0000-0209.testustar00rootroot00000000000000librecast/test/router/0000-0210.test000077700000000000000000000000001502456746400212502../0000-0210.testustar00rootroot00000000000000librecast/test/router/0000-0211.test000077700000000000000000000000001502456746400212522../0000-0211.testustar00rootroot00000000000000librecast/test/router/0000-0212.test000077700000000000000000000000001502456746400212542../0000-0212.testustar00rootroot00000000000000librecast/test/router/0000-0213.test000077700000000000000000000000001502456746400212562../0000-0213.testustar00rootroot00000000000000librecast/test/router/0000-0214.test000077700000000000000000000000001502456746400212602../0000-0214.testustar00rootroot00000000000000librecast/test/router/0000-0215.test000077700000000000000000000000001502456746400212622../0000-0215.testustar00rootroot00000000000000librecast/test/router/0000-0216.test000077700000000000000000000000001502456746400212642../0000-0216.testustar00rootroot00000000000000librecast/test/rq/000077500000000000000000000000001502456746400144445ustar00rootroot00000000000000librecast/test/rq/0000-0008.test000077700000000000000000000000001502456746400203642../0000-0008.testustar00rootroot00000000000000librecast/test/rq/0000-0039.test000077700000000000000000000000001502456746400203742../0000-0039.testustar00rootroot00000000000000librecast/test/rq/0000-0040.test000077700000000000000000000000001502456746400203542../0000-0040.testustar00rootroot00000000000000librecast/test/rq/0000-0045.test000077700000000000000000000000001502456746400203662../0000-0045.testustar00rootroot00000000000000librecast/test/rq/0000-0055.test000077700000000000000000000000001502456746400203702../0000-0055.testustar00rootroot00000000000000librecast/test/rq/0000-0056.test000077700000000000000000000000001502456746400203722../0000-0056.testustar00rootroot00000000000000librecast/test/rq/0000-0060.test000077700000000000000000000000001502456746400203602../0000-0060.testustar00rootroot00000000000000librecast/test/rq/0000-0069.test000077700000000000000000000000001502456746400204022../0000-0069.testustar00rootroot00000000000000librecast/test/rq/0000-0071.test000077700000000000000000000000001502456746400203642../0000-0071.testustar00rootroot00000000000000librecast/test/rq/0000-0075.test000077700000000000000000000000001502456746400203742../0000-0075.testustar00rootroot00000000000000librecast/test/rq/0000-0077.test000077700000000000000000000000001502456746400204002../0000-0077.testustar00rootroot00000000000000librecast/test/rq/0000-0091.test000077700000000000000000000000001502456746400203702../0000-0091.testustar00rootroot00000000000000librecast/test/rq/0000-0093.test000077700000000000000000000000001502456746400203742../0000-0093.testustar00rootroot00000000000000librecast/test/rq/0000-0110.test000077700000000000000000000000001502456746400203502../0000-0110.testustar00rootroot00000000000000librecast/test/rq/0000-0111.test000077700000000000000000000000001502456746400203522../0000-0111.testustar00rootroot00000000000000librecast/test/rq/0000-0115.test000077700000000000000000000000001502456746400203622../0000-0115.testustar00rootroot00000000000000librecast/test/rq/0000-0116.test000077700000000000000000000000001502456746400203642../0000-0116.testustar00rootroot00000000000000librecast/test/rq/0000-0117.test000077700000000000000000000000001502456746400203662../0000-0117.testustar00rootroot00000000000000librecast/test/sendrecv/000077500000000000000000000000001502456746400156335ustar00rootroot00000000000000librecast/test/sendrecv/0000-0006.test000077700000000000000000000000001502456746400215472../0000-0006.testustar00rootroot00000000000000librecast/test/sendrecv/0000-0007.test000077700000000000000000000000001502456746400215512../0000-0007.testustar00rootroot00000000000000librecast/test/sendrecv/0000-0008.test000077700000000000000000000000001502456746400215532../0000-0008.testustar00rootroot00000000000000librecast/test/sendrecv/0000-0012.test000077700000000000000000000000001502456746400215412../0000-0012.testustar00rootroot00000000000000librecast/test/sendrecv/0000-0013.test000077700000000000000000000000001502456746400215432../0000-0013.testustar00rootroot00000000000000librecast/test/sendrecv/0000-0014.test000077700000000000000000000000001502456746400215452../0000-0014.testustar00rootroot00000000000000librecast/test/sendrecv/0000-0015.test000077700000000000000000000000001502456746400215472../0000-0015.testustar00rootroot00000000000000librecast/test/sendrecv/0000-0016.test000077700000000000000000000000001502456746400215512../0000-0016.testustar00rootroot00000000000000librecast/test/sendrecv/0000-0018.test000077700000000000000000000000001502456746400215552../0000-0018.testustar00rootroot00000000000000librecast/test/sendrecv/0000-0019.test000077700000000000000000000000001502456746400215572../0000-0019.testustar00rootroot00000000000000librecast/test/sendrecv/0000-0020.test000077700000000000000000000000001502456746400215372../0000-0020.testustar00rootroot00000000000000librecast/test/sendrecv/0000-0021.test000077700000000000000000000000001502456746400215412../0000-0021.testustar00rootroot00000000000000librecast/test/sendrecv/0000-0036.test000077700000000000000000000000001502456746400215552../0000-0036.testustar00rootroot00000000000000librecast/test/sendrecv/0000-0037.test000077700000000000000000000000001502456746400215572../0000-0037.testustar00rootroot00000000000000librecast/test/sendrecv/0000-0038.test000077700000000000000000000000001502456746400215612../0000-0038.testustar00rootroot00000000000000librecast/test/sendrecv/0000-0039.test000077700000000000000000000000001502456746400215632../0000-0039.testustar00rootroot00000000000000librecast/test/sendrecv/0000-0040.test000077700000000000000000000000001502456746400215432../0000-0040.testustar00rootroot00000000000000librecast/test/sendrecv/0000-0042.test000077700000000000000000000000001502456746400215472../0000-0042.testustar00rootroot00000000000000librecast/test/sendrecv/0000-0043.test000077700000000000000000000000001502456746400215512../0000-0043.testustar00rootroot00000000000000librecast/test/sendrecv/0000-0044.test000077700000000000000000000000001502456746400215532../0000-0044.testustar00rootroot00000000000000librecast/test/sendrecv/0000-0045.test000077700000000000000000000000001502456746400215552../0000-0045.testustar00rootroot00000000000000librecast/test/sendrecv/0000-0057.test000077700000000000000000000000001502456746400215632../0000-0057.testustar00rootroot00000000000000librecast/test/sendrecv/0000-0058.test000077700000000000000000000000001502456746400215652../0000-0058.testustar00rootroot00000000000000librecast/test/sendrecv/0000-0059.test000077700000000000000000000000001502456746400215672../0000-0059.testustar00rootroot00000000000000librecast/test/sendrecv/0000-0060.test000077700000000000000000000000001502456746400215472../0000-0060.testustar00rootroot00000000000000librecast/test/sendrecv/0000-0069.test000077700000000000000000000000001502456746400215712../0000-0069.testustar00rootroot00000000000000librecast/test/sendrecv/0000-0070.test000077700000000000000000000000001502456746400215512../0000-0070.testustar00rootroot00000000000000librecast/test/sendrecv/0000-0071.test000077700000000000000000000000001502456746400215532../0000-0071.testustar00rootroot00000000000000librecast/test/sendrecv/0000-0072.test000077700000000000000000000000001502456746400215552../0000-0072.testustar00rootroot00000000000000librecast/test/sendrecv/0000-0110.test000077700000000000000000000000001502456746400215372../0000-0110.testustar00rootroot00000000000000librecast/test/sendrecv/0000-0111.test000077700000000000000000000000001502456746400215412../0000-0111.testustar00rootroot00000000000000librecast/test/sendrecv/0000-0115.test000077700000000000000000000000001502456746400215512../0000-0115.testustar00rootroot00000000000000librecast/test/skel.c000066400000000000000000000003431502456746400151240ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2024 Brett Sheffield */ #include "test.h" int main(void) { char name[] = "testname"; test_name(name); return test_status; } librecast/test/socketpair/000077500000000000000000000000001502456746400161665ustar00rootroot00000000000000librecast/test/socketpair/0000-0006.test000077700000000000000000000000001502456746400221022../0000-0006.testustar00rootroot00000000000000librecast/test/socketpair/0000-0007.test000077700000000000000000000000001502456746400221042../0000-0007.testustar00rootroot00000000000000librecast/test/socketpair/0000-0008.test000077700000000000000000000000001502456746400221062../0000-0008.testustar00rootroot00000000000000librecast/test/socketpair/0000-0093.test000077700000000000000000000000001502456746400221162../0000-0093.testustar00rootroot00000000000000librecast/test/sync/000077500000000000000000000000001502456746400147765ustar00rootroot00000000000000librecast/test/sync/0000-0055.test000077700000000000000000000000001502456746400207222../0000-0055.testustar00rootroot00000000000000librecast/test/sync/0000-0056.test000077700000000000000000000000001502456746400207242../0000-0056.testustar00rootroot00000000000000librecast/test/sync/0000-0110.test000077700000000000000000000000001502456746400207022../0000-0110.testustar00rootroot00000000000000librecast/test/sync/0000-0111.test000077700000000000000000000000001502456746400207042../0000-0111.testustar00rootroot00000000000000librecast/test/sync/0000-0112.test000077700000000000000000000000001502456746400207062../0000-0112.testustar00rootroot00000000000000librecast/test/sync/0000-0114.test000077700000000000000000000000001502456746400207122../0000-0114.testustar00rootroot00000000000000librecast/test/sync/0000-0116.test000077700000000000000000000000001502456746400207162../0000-0116.testustar00rootroot00000000000000librecast/test/sync/0000-0117.test000077700000000000000000000000001502456746400207202../0000-0117.testustar00rootroot00000000000000librecast/test/sync/0000-0121.test000077700000000000000000000000001502456746400207062../0000-0121.testustar00rootroot00000000000000librecast/test/test.c000066400000000000000000000132031502456746400151440ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2020-2023 Brett Sheffield */ #include "test.h" #include #include #include #include #include #include #include #define DEFAULT_TERM_COLS 80 #define TESTID_WIDTH 16 #define SPINAL_TAP 11 int COLS = DEFAULT_TERM_COLS; int MSGW; int test_status = TEST_OK; /* test exit status (not a count of failures) */ int capreqd = 0; int capfail = 0; sem_t log_lock; static int _vscprintf (const char * format, va_list argp) { int r; va_list argc; va_copy(argc, argp); r = vsnprintf(NULL, 0, format, argc); va_end(argc); return r; } void vfail_msg(char *msg, va_list argp) { char *b; b = malloc(_vscprintf(msg, argp) + 1); pthread_cleanup_push(free, b); vsprintf(b, msg, argp); printf("\n%-*s%-*s", SPINAL_TAP, " ", MSGW, b); pthread_cleanup_pop(1); /* free(b); */ test_status = TEST_FAIL; } static int test_assert_va(int condition, int verbose, char *msg, va_list argp) { char *b; va_list copy; va_copy(copy, argp); b = malloc(_vscprintf(msg, argp) + 6); pthread_cleanup_push(free, b); if (b) vsprintf(b, msg, copy); if (!condition) { vfail_msg(msg, argp); if (b) test_log("[FAIL] %s\n", b); } else if (b && verbose) { test_log("[ OK ] %s\n", b); } pthread_cleanup_pop(1); /* free(b); */ va_end(argp); return condition; } int test_assert(int condition, char *msg, ...) { va_list argp; va_start(argp, msg); return test_assert_va(condition, 1, msg, argp); } /* assert quietly - only log on failure */ int test_assert_q(int condition, char *msg, ...) { va_list argp; va_start(argp, msg); return test_assert_va(condition, 0, msg, argp); } int test_strcmp(char *str1, char *str2, char *msg, ...) { if (str1 == NULL || str2 == NULL || strcmp(str1, str2)) { va_list argp; va_start(argp, msg); vfail_msg(msg, argp); va_end(argp); return 0; } return 1; } int test_strncmp(char *str1, char *str2, size_t len, char *msg, ...) { if (str1 == NULL || str2 == NULL || strncmp(str1, str2, len)) { va_list argp; va_start(argp, msg); vfail_msg(msg, argp); va_end(argp); return 0; } return 1; } int test_expect(char *expected, char *got) { return test_strcmp(expected, got, "expected: '%s', got: '%s'", expected, got); } int test_expectn(char *expected, char *got, size_t len) { return test_strncmp(expected, got, len, "expected: '%s', got: '%s'", expected, got); } void test_log(char *msg, ...) { char *b; va_list argp; va_start(argp, msg); b = malloc(_vscprintf(msg, argp) + 1); pthread_cleanup_push(free, b); vsprintf(b, msg, argp); /* In order to keep the test logs clean we try to wait for other threads * to finish before logging, but if we need to wait more than a second, * give up and log anyway. A deadlock between two test threads is best * avoided. */ struct timespec ts; clock_gettime(CLOCK_REALTIME, &ts); ts.tv_sec++; sem_timedwait(&log_lock, &ts); fprintf(stderr, "%s", b); fflush(stderr); sem_post(&log_lock); va_end(argp); pthread_cleanup_pop(1); /* free(b); */ } static void init_terminal(void) { #if HAVE_SYS_IOCTL_H if (isatty(fileno(stdout))) { /* get terminal size */ struct winsize w; COLS = (ioctl(fileno(stdout), TIOCGWINSZ, &w) != -1) ? w.ws_col : DEFAULT_TERM_COLS; } else COLS = DEFAULT_TERM_COLS; #endif MSGW = COLS - TESTID_WIDTH; } void test_init(void) { static int runonce; if (runonce++) return; init_terminal(); sem_init(&log_lock, 0, 1); } void test_name(char *str, ...) { char *b; va_list argp; int do_exit = 1; test_init(); va_start(argp, str); b = malloc(_vscprintf(str, argp) + 1); vsprintf(b, str, argp); test_log(" %s\n", b); test_log("\n"); if (capfail) { printf("%-*s", MSGW, "----- requires capabilities (skipping) -----"); } else if (!capreqd && geteuid() == 0) { printf("%-*s", MSGW, "----- does not require root (skipping) -----"); } else if (test_status != TEST_OK) { printf("%-*s", MSGW, "----- (skipping) -----"); } else { printf("%-*s", MSGW, b); do_exit ^= do_exit; } fflush(stdout); /* ensure the test name is displayed in case of SIGABORT */ va_end(argp); free(b); if (do_exit) exit(test_status); } int test_skip(char *str, ...) { char *b; va_list argp; init_terminal(); sem_init(&log_lock, 0, 1); va_start(argp, str); b = malloc(_vscprintf(str, argp) + 1); vsprintf(b, str, argp); printf("(skipped) %-*s", MSGW - 10, b); test_log(" %s\n", b); test_log("\n"); va_end(argp); free(b); return TEST_WARN; } void test_rusage(void) { struct rusage ru = {0}; if (getrusage(RUSAGE_SELF, &ru)) { perror("getrusage"); return; } test_log("user : %lis.%li\n", ru.ru_utime.tv_sec, ru.ru_utime.tv_usec); test_log("system: %lis.%li\n", ru.ru_stime.tv_sec, ru.ru_stime.tv_usec); test_log("maxrss: %li\n", ru.ru_maxrss); test_log("ixrss: %li\n", ru.ru_ixrss); test_log("idrss: %li\n", ru.ru_idrss); test_log("isrss: %li\n", ru.ru_isrss); test_log("minflt: %li\n", ru.ru_minflt); test_log("majflt: %li\n", ru.ru_majflt); test_log("nswap: %li\n", ru.ru_nswap); test_log("inblock: %li\n", ru.ru_inblock); test_log("oublock: %li\n", ru.ru_oublock); test_log("msgsnd: %li\n", ru.ru_msgsnd); test_log("msgrcv: %li\n", ru.ru_msgrcv); test_log("nsignals: %li\n", ru.ru_nsignals); test_log("nvcsw: %li\n", ru.ru_nvcsw); test_log("nivcsw: %li\n", ru.ru_nivcsw); } void test_cap_require(int cap) { (void) cap; // TODO check for capabilities on Linux if (geteuid()) capfail++; capreqd++; } void test_require_linux(void) { #ifndef __linux__ init_terminal(); printf("%-*s", MSGW, "----- linux only (skipping) -----"); exit(test_status); #endif } librecast/test/test.h000066400000000000000000000022501502456746400151510ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2020-2022 Brett Sheffield */ #ifndef _TEST_H #define _TEST_H 1 #ifdef __linux__ # define _GNU_SOURCE #endif #include "../src/config.h" #include #include #include #include #include #include "valgrind.h" #if HAVE_SYS_ENDIAN_H # include #endif #ifdef __linux__ #include #else #define CAP_NET_ADMIN 12 #define CAP_NET_RAW 13 #endif enum { TEST_ERR = -1, TEST_OK = 0, TEST_WARN = 1, TEST_FAIL = 2, TEST_UNKN = 3 }; extern int test_status; void test_init(void); void fail_msg(char *msg, ...); int test_assert(int condition, char *msg, ...); int test_assert_q(int condition, char *msg, ...); int test_strcmp(char *str1, char *str2, char *msg, ...); int test_strncmp(char *str1, char *str2, size_t len, char *msg, ...); int test_expect(char *expected, char *got); int test_expectn(char *expected, char *got, size_t len); void test_log(char *msg, ...); void test_name(char *str, ...); int test_skip(char *str, ...); void test_cap_require(int cap); void test_require_linux(void); #endif /* _TEST_H */ librecast/test/testdata.c000066400000000000000000000135751502456746400160120ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2023 Brett Sheffield */ #include "testdata.h" #include static size_t getbufsize(void) { int buflen = sysconf(_SC_PAGESIZE); return (size_t)(16 * buflen); } int test_random_bytes(void *ptr, size_t sz) { FILE *fr; size_t byt = 0, bi; fr = fopen("/dev/urandom", "r"); if (!fr) return -1; while (byt < sz) { bi = fread(ptr, 1, sz - byt, fr); if (bi > 0) { byt += bi; ptr = (char *)ptr + bi; } } fclose(fr); return 0; } int test_sparsify_fd(int fd, size_t sz) { FILE *f; int fdup; fdup = dup(fd); f = fdopen(fdup, "r+"); if (!f) return -1; fseek(f, sz - 1, SEEK_SET); fputc(0, f); fclose(f); return 0; } static int test_randomize_file(int fd, size_t sz) { FILE *f, *fr; char buf[BUFSIZ]; size_t byt = 0, bi; int fdup; fdup = dup(fd); f = fdopen(fdup, "w+"); if (!f) return -1; fr = fopen("/dev/urandom", "r"); if (!fr) goto exit_0; while (byt < sz) { bi = fread(buf, 1, MIN(sizeof buf, sz - byt), fr); if (bi > 0) { byt += fwrite(buf, 1, bi, f); } } fclose(fr); exit_0: fclose(f); return 0; } int test_data_file(char *filename, size_t sz, int flags) { int fd; if (flags & TEST_TMP) { if ((fd = mkstemp(filename)) == -1) { perror("mkstemp"); return -1; } } else if ((fd = open(filename, flags)) == -1) { perror("open"); return -1; } if (flags & TEST_RND) { if (test_randomize_file(fd, sz) == -1) { close(fd); return -1; } } else if (sz > 0) { /* size requested, but no data => sparse */ if (test_sparsify_fd(fd, sz) == -1) { close(fd); return -1; } } return fd; } int test_random_meta(const char *path, int flags) { int rc = 0; if (flags & TEST_OWN) { uid_t uid; gid_t gid; uid = arc4random_uniform(1024); gid = arc4random_uniform(1024); rc = chown(path, uid, gid); if (rc) return rc; } if (flags & TEST_MOD) { mode_t mode; mode = arc4random_uniform(0777); rc = chmod(path, mode); } return rc; } int test_createtesttree(const char *path, off_t max_filesz, int max_files, int max_dirs, int depth, int flags) { char template[] = "test-XXXXXX"; char filename[] = "test-XXXXXX"; char cwd[PATH_MAX]; char owd[PATH_MAX]; size_t len; int fd, max, rc; if (!getcwd(owd, sizeof owd)) return -1; rc = chdir(path); if (!getcwd(cwd, sizeof cwd)) return -1; if (rc == -1) { perror(path); return -1; } len = strlen(template); max = arc4random_uniform(max_files); for (int i = 0; i < max; i++) { memcpy(filename, template, len); fd = mkstemp(filename); if (fd == -1) { perror("mkstemp"); break; } test_randomize_file(fd, arc4random_uniform(max_filesz)); test_random_meta(filename, flags); close(fd); } max = arc4random_uniform(max_dirs); if (!max) max = 1; for (int i = 0; i < max; i++) { memcpy(filename, template, len); if (mkdtemp(filename)) { test_random_meta(filename, flags); if (depth > 0) test_createtesttree(filename, max_filesz, max_files, max_dirs, depth - 1, flags); } } return chdir(owd); } int test_createtestdir(char *testprog, char **dir, const char *srcdst) { char template[] = ".tmp.XXXXXX"; size_t buflen, sz; int rc; /* find length of required buffer and allocate */ sz = strlen(testprog) - 5; /* strip .test */ buflen = (size_t)snprintf(NULL, 0, "%.*s.%s%s", (int)sz, testprog, srcdst, template) + 1; *dir = malloc(buflen); if (!*dir) return -1; /* build template string for directory name */ rc = snprintf(*dir, buflen, "%.*s.%s%s", (int)sz, testprog, srcdst, template); if (rc != (int)(buflen - 1)) goto err_free_dir; /* create temp directory */ if (!mkdtemp(*dir)) goto err_free_dir; fprintf(stderr, "directory '%s' created\n", *dir); return 0; err_free_dir: free(*dir); return -1; } int test_createtestdirs(char *testprog, char **src, char **dst) { int rc; rc = test_createtestdir(testprog, src, "src"); if (rc == -1) return -1; rc = test_createtestdir(testprog, dst, "dst"); if (rc == 0) return 0; rc = errno; free(src); errno = rc; return -1; } int test_data_size(char *filename, size_t sz) { struct stat sb; if (stat(filename, &sb) == -1) return -1; if ((sb.st_mode & S_IFMT) != S_IFREG) return -1; if ((size_t)sb.st_size != sz) return -1; return 0; } int test_hash_file(const char *filename, unsigned char *hash, size_t hashlen, char *buf, size_t buflen) { hash_state state; FILE *f; size_t byt; int free_buf = (buf == NULL); /* was buffer provided ? */ if (!buf) { buflen = getbufsize(); buf = malloc(buflen); if (!buf) return -1; } f = fopen(filename, "r"); if (!f) goto exit_0; hash_init(&state, NULL, 0, hashlen); while ((byt = fread(buf, 1, buflen, f))) { hash_update(&state, (unsigned char *)buf, byt); } hash_final(&state, hash, hashlen); fclose(f); exit_0: if (free_buf) free(buf); return 0; } int test_file_match(const char *file1, const char *file2) { unsigned char hash[2][HASHSIZE]; char buf[BUFSIZ]; memset(hash, 0, sizeof hash); test_hash_file(file1, hash[0], HASHSIZE, buf, sizeof buf); test_hash_file(file2, hash[1], HASHSIZE, buf, sizeof buf); fprintf(stderr, "%s: ", file1); hash_hex_debug(stderr, hash[0], HASHSIZE); fprintf(stderr, "%s: ", file2); hash_hex_debug(stderr, hash[1], HASHSIZE); return memcmp(hash[0], hash[1], HASHSIZE); } int test_file_scratch(const char *filename, long offset, size_t len) { char *buf; FILE *f, *fr; size_t byt = 0, bi; int buflen = MIN(getpagesize(), (int)len); if (!len) return 0; f = fopen(filename, "r+"); if (!f) return -1; fr = fopen("/dev/urandom", "r"); if (!fr) goto exit_0; if (offset < 0) { if (fseek(f, offset, SEEK_END) == -1) goto exit_1; } else if (offset > 0) { if (fseek(f, offset, SEEK_SET) == -1) goto exit_1; } buf = malloc(buflen); if (!buf) goto exit_1; while (byt < len) { bi = fread(buf, 1, MIN((size_t)buflen, len - byt), fr); if (bi > 0) { byt += fwrite(buf, 1, bi, f); } } free(buf); exit_1: fclose(fr); exit_0: fclose(f); return 0; } librecast/test/testdata.h000066400000000000000000000056441502456746400160150ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2023 Brett Sheffield */ #ifndef _TESTDATA_H #define _TESTDATA_H 1 #include "test.h" #include #include #include #include #include #include #include #include #include #include enum { TEST_TMP = 1, TEST_RND = 2, TEST_OWN = 4, TEST_MOD = 8, }; /* write sz random bytes to ptr */ int test_random_bytes(void *ptr, size_t sz); /* create test file with of sz bytes at path filename * * flags: * TEST_TMP - if set, a temp file is created using filename as the template. * TEST_RND - fill the file with sz random bytes * * if sz > 0 but TEST_RND is not set, a sparse file is created. */ int test_data_file(char *filename, size_t sz, int flags); /* verify filename is a regular file and is correct size * return 0 if correct, -1 on error */ int test_data_size(char *filename, size_t sz); /* hash file * filename - file to hash * hash - buffer to return hash in * hashlen - length of hash buffer * buf - either NULL or a pointer to a preallocated buffer for file I/O * buflen - length of buf in bytes * returns 0 on success, -1 on error, setting errno */ int test_hash_file(const char *filename, unsigned char *hash, size_t hashlen, char *buf, size_t buflen); /* hash files and confirm data matches, return 0 on match, nonzero fail */ int test_file_match(const char *file1, const char *file2); /* write len random bytes to file, starting at offset off * returns 0 on success, -1 on error, setting errno */ int test_file_scratch(const char *filename, long offset, size_t len); /* extend file sparsely to sz bytes */ int test_sparsify_fd(int fd, size_t sz); /* randomize file metadata * path must be an existing directory * flags can be: * - TEST_OWN - randomize uid and gid * - TEST_MOD - randomize permissions */ int test_random_meta(const char *path, int flags); /* create a directory tree of files and directories with directories nested * depth levels deep, up to max_files files and max_dirs directories in each * level. Fill files with up to max_filesz random bytes. * path must be an existing directory * flags can be: * - TEST_OWN - randomize uid and gid * - TEST_MOD - randomize permissions */ int test_createtesttree(const char *path, off_t max_filesz, int max_files, int max_dirs, int depth, int flags); /* create a pair of source and destination directories using the template * of the form 0000-0000.{src,dst}.tmp.XXXXXX based on the test name. * testprog should be passed as basename(argv[0]) * Both src and dst need to be free()ed after use. */ int test_createtestdirs(char *testprog, char **src, char **dst); /* create a single test directory as above. srcdst must be "src" or "dst" */ int test_createtestdir(char *testprog, char **dir, const char *srcdst); #endif /* _TESTDATA_H */ librecast/test/testnet.c000066400000000000000000000070571502456746400156650ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2022-2023 Brett Sheffield */ #include "test.h" #include #include #ifdef __linux__ # include # include #endif #include #include #include #ifndef AF_LINK # ifdef AF_PACKET # define AF_LINK AF_PACKET # endif #endif unsigned int get_invalid_ifx(void) { char ifname[IF_NAMESIZE]; for (unsigned int ifx = 1; ifx < UINT_MAX; ifx++) { if (!if_indextoname(ifx, ifname)) return ifx; } return 0; } /* find an interface that supports multicast */ unsigned get_multicast_if(void) { unsigned ifidx = 0; /* create tap interface and bring it up */ char ifname[IFNAMSIZ] = {0}; #ifdef __linux__ lc_tuntap_create(ifname, IFF_TAP | IFF_NO_PI); lc_ctx_t *lctx = lc_ctx_new(); lc_link_set(lctx, ifname, 1); lc_ctx_free(lctx); ifidx = if_nametoindex(ifname); #endif if (!ifidx) { test_log("unable to create tap device: %s\n", strerror(errno)); /* failed to create tap, find multicast capable interface */ struct ifaddrs *ifa = NULL, *ifap = NULL; test_assert(getifaddrs(&ifa) != -1, "getifaddrs(): %s", strerror(errno)); for (ifap = ifa; ifap; ifap = ifap->ifa_next) { if (!(ifap->ifa_flags & IFF_MULTICAST)) continue; /* we don't want the loopback interface */ if (ifap->ifa_flags & IFF_LOOPBACK) continue; if (ifap->ifa_addr == NULL) continue; if (ifap->ifa_addr->sa_family != AF_INET6) continue; ifidx = if_nametoindex(ifap->ifa_name); test_log("found multicast interface %s [%u]\n", ifap->ifa_name, ifidx); break; } freeifaddrs(ifa); } else { test_log("tap %s created\n", ifname); } return ifidx; } int test_net_level(void) { struct ifaddrs *ifaddr; int ifaces = 0; int ifup = 0; int mcast = 0; int addr6 = 0; int addr4 = 0; int level = 0; int mroutes = 0; char * have_multicast = getenv("HAVE_MULTICAST_ROUTES"); test_init(); test_log("Checking network connectivity...\n"); if (getifaddrs(&ifaddr) == -1) return -1; for (struct ifaddrs *ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) { switch (ifa->ifa_addr->sa_family) { case AF_LINK: ifaces++; if (ifa->ifa_flags & IFF_UP) { ifup++; /* test MULTICAST flag, skip loopback interfaces */ if (ifa->ifa_flags & IFF_LOOPBACK) break; if (ifa->ifa_flags & IFF_MULTICAST) mcast++; } break; case AF_INET6: if (ifa->ifa_flags & IFF_UP) addr6++; break; case AF_INET: if (ifa->ifa_flags & IFF_UP) addr4++; break; } } freeifaddrs(ifaddr); test_log("have_multicast: %s\n", have_multicast); if (have_multicast) mroutes = atoi(have_multicast); test_log(" %i network interfaces found\n", ifaces); test_log(" %i network interfaces up\n", ifup); test_log(" %i MULTICAST interfaces up\n", mcast); test_log(" %i IPv6 addresses\n", addr6); test_log(" %i IPv4 addresses\n", addr4); test_log(" %i multicast routes\n", mroutes); level |= (ifaces > 0); level |= (ifup > 0) << 1; level |= (addr4 > 0) << 2; level |= (addr6 > 0) << 3; level |= (mcast > 0) << 4; level |= (mroutes > 0) << 5; test_log("connectivity level = %i (%06b)\n", level, level); return level; } int test_require_net(int required) { int lvl = test_net_level(); if ((lvl & required) != required) { test_log("------------------------------------------------------\n"); test_log("Required network level not met. Skipping test. \n"); test_log("(%06b/%06b)\n", lvl, required); test_log("------------------------------------------------------\n"); exit(TEST_WARN); } return lvl; } librecast/test/testnet.h000066400000000000000000000021501502456746400156570ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2022-2023 Brett Sheffield */ #include "test.h" #include #include #include #include /* levels of network availability. Each level requires the previous */ enum { TEST_NET_NONE = 0, /* no network interfaces detected */ TEST_NET_IFACE = 1,/* at least one interface detected */ TEST_NET_UP = 2, /* at least one interface is up */ TEST_NET_ADDR4 = 4, /* IPv4 network address found */ TEST_NET_ADDR6 = 8, /* IPv6 network address found */ TEST_NET_MCAST = 16,/* device with MULTICAST flag set found */ TEST_NET_MROUTE = 32 /* has multicast routes */ }; #define TEST_NET_BASIC TEST_NET_IFACE | TEST_NET_UP | TEST_NET_ADDR6 | TEST_NET_MCAST | TEST_NET_MROUTE /* find an invalid interface index */ unsigned int get_invalid_ifx(void); /* find an interface that supports multicast */ unsigned get_multicast_if(void); /* return level of network available */ int test_net_level(void); /* exit test with TEST_WARN unless network level is met */ int test_require_net(int required); librecast/test/testsync.c000066400000000000000000000052201502456746400160410ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2023-2024 Brett Sheffield */ #include "../src/config.h" #define _XOPEN_SOURCE 700 /* for nftw() */ #include #include "test.h" #include "testdata.h" #include #include #include static char *rsrc, *rdst, *owd; /* check mode, owner, group, times */ int statcmp_sb(const struct stat *ssb, const struct stat *dsb, const char *dst) { if ((ssb->st_mode & S_IFMT) == S_IFLNK) return 0; /* don't bother with symlinks */ test_assert(ssb->st_mode == dsb->st_mode, "st_mode: '%s' %o %o", dst, ssb->st_mode, dsb->st_mode); test_assert(ssb->st_uid == dsb->st_uid, "st_uid: '%s'", dst); test_assert(ssb->st_gid == dsb->st_gid, "st_gid: '%s'", dst); if ((ssb->st_mode & S_IFMT) != S_IFDIR) { /* check size, but not for directories */ test_assert(ssb->st_size == dsb->st_size, "st_size: '%s'", dst); } #ifndef HAVE_UTIMENSAT /* without utimensat(), we only have microsecond precision */ ssb->st_mtim.tv_nsec /= 1000; ssb->st_mtim.tv_nsec *= 1000; ssb->st_atim.tv_nsec /= 1000; ssb->st_atim.tv_nsec *= 1000; #endif /* No point testing atime unless the filesystem is mounted noatime */ /* test_assert(ssb.st_atim.tv_nsec == dsb.st_atim.tv_nsec, "st_atim: '%s'", dst); */ test_assert(ssb->st_mtim.tv_nsec == dsb->st_mtim.tv_nsec, "st_mtim: '%s'", dst); return 0; } /* check mode, owner, group, times */ int statcmp(const char *src, const char *dst) { struct stat ssb, dsb; int rc; rc = stat(src, &ssb); if (!test_assert(rc == 0, "stat '%s'", src)) return -1; rc = stat(dst, &dsb); if (!test_assert(rc == 0, "stat '%s'", dst)) return -1; return statcmp_sb(&ssb, &dsb, dst); } static int verify_dst(const char *fpath, const struct stat *sb, int typeflag, struct FTW *ftwbuf) { (void) typeflag, (void) ftwbuf; struct stat dsb; int rc; if (chdir(rdst) == -1) return -1; rc = stat(fpath, &dsb); if (!rc) rc = statcmp_sb(sb, &dsb, fpath); if (chdir(rsrc) == -1) return -1; return rc; } void test_verify_dirs(const char *src, const char *dst) { int n = 0, rc; statcmp(src, dst); owd = getcwd(NULL, 0); assert(owd); rsrc = realpath(src, NULL); rdst = realpath(dst, NULL); test_log("src: %s\n", src); test_log("dst: %s\n", dst); test_log("rsrc: %s\n", rsrc); test_log("rdst: %s\n", rdst); if (chdir(rsrc) == -1) goto err_free; rc = nftw(".", &verify_dst, 32, 0); if (!test_assert(rc == 0, "nftw() returned %i", rc)) goto err_free; test_log("%i entries verified\n", n); test_assert(test_status == TEST_OK, "source and destination trees match"); if (chdir(owd) == -1) perror("chdir"); err_free: free(rsrc); free(rdst); free(owd); } librecast/test/testsync.h000066400000000000000000000006141502456746400160500ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ /* Copyright (c) 2023 Brett Sheffield */ #ifndef _TESTSYNC_H #define _TESTSYNC_H 1 /* check mode, owner, group, times */ int statcmp(const char *src, const char *dst); /* verify src and dst match (recursive directory compare) */ void test_verify_dirs(const char *src, const char *dst); #endif /* _TESTSYNC_H */ librecast/test/tsan/000077500000000000000000000000001502456746400147675ustar00rootroot00000000000000librecast/test/tsan/0000-0003.test000077700000000000000000000000001502456746400206752../0000-0003.testustar00rootroot00000000000000librecast/test/tsan/0000-0005.test000077700000000000000000000000001502456746400207012../0000-0005.testustar00rootroot00000000000000librecast/test/tsan/0000-0006.test000077700000000000000000000000001502456746400207032../0000-0006.testustar00rootroot00000000000000librecast/test/tsan/0000-0007.test000077700000000000000000000000001502456746400207052../0000-0007.testustar00rootroot00000000000000librecast/test/tsan/0000-0008.test000077700000000000000000000000001502456746400207072../0000-0008.testustar00rootroot00000000000000librecast/test/tsan/0000-0009.test000077700000000000000000000000001502456746400207112../0000-0009.testustar00rootroot00000000000000librecast/test/tsan/0000-0010.test000077700000000000000000000000001502456746400206712../0000-0010.testustar00rootroot00000000000000librecast/test/tsan/0000-0011.test000077700000000000000000000000001502456746400206732../0000-0011.testustar00rootroot00000000000000librecast/test/tsan/0000-0012.test000077700000000000000000000000001502456746400206752../0000-0012.testustar00rootroot00000000000000librecast/test/tsan/0000-0013.test000077700000000000000000000000001502456746400206772../0000-0013.testustar00rootroot00000000000000librecast/test/tsan/0000-0014.test000077700000000000000000000000001502456746400207012../0000-0014.testustar00rootroot00000000000000librecast/test/tsan/0000-0015.test000077700000000000000000000000001502456746400207032../0000-0015.testustar00rootroot00000000000000librecast/test/tsan/0000-0016.test000077700000000000000000000000001502456746400207052../0000-0016.testustar00rootroot00000000000000librecast/test/tsan/0000-0017.test000077700000000000000000000000001502456746400207072../0000-0017.testustar00rootroot00000000000000librecast/test/tsan/0000-0018.test000077700000000000000000000000001502456746400207112../0000-0018.testustar00rootroot00000000000000librecast/test/tsan/0000-0019.test000077700000000000000000000000001502456746400207132../0000-0019.testustar00rootroot00000000000000librecast/test/tsan/0000-0020.test000077700000000000000000000000001502456746400206732../0000-0020.testustar00rootroot00000000000000librecast/test/tsan/0000-0021.test000077700000000000000000000000001502456746400206752../0000-0021.testustar00rootroot00000000000000librecast/test/tsan/0000-0022.test000077700000000000000000000000001502456746400206772../0000-0022.testustar00rootroot00000000000000librecast/test/tsan/0000-0023.test000077700000000000000000000000001502456746400207012../0000-0023.testustar00rootroot00000000000000librecast/test/tsan/0000-0024.test000077700000000000000000000000001502456746400207032../0000-0024.testustar00rootroot00000000000000librecast/test/tsan/0000-0025.test000077700000000000000000000000001502456746400207052../0000-0025.testustar00rootroot00000000000000librecast/test/tsan/0000-0026.test000077700000000000000000000000001502456746400207072../0000-0026.testustar00rootroot00000000000000librecast/test/tsan/0000-0027.test000077700000000000000000000000001502456746400207112../0000-0027.testustar00rootroot00000000000000librecast/test/tsan/0000-0028.test000077700000000000000000000000001502456746400207132../0000-0028.testustar00rootroot00000000000000librecast/test/tsan/0000-0029.test000077700000000000000000000000001502456746400207152../0000-0029.testustar00rootroot00000000000000librecast/test/tsan/0000-0030.test000077700000000000000000000000001502456746400206752../0000-0030.testustar00rootroot00000000000000librecast/test/tsan/0000-0031.test000077700000000000000000000000001502456746400206772../0000-0031.testustar00rootroot00000000000000librecast/test/tsan/0000-0032.test000077700000000000000000000000001502456746400207012../0000-0032.testustar00rootroot00000000000000librecast/test/tsan/0000-0033.test000077700000000000000000000000001502456746400207032../0000-0033.testustar00rootroot00000000000000librecast/test/tsan/0000-0034.test000077700000000000000000000000001502456746400207052../0000-0034.testustar00rootroot00000000000000librecast/test/tsan/0000-0035.test000077700000000000000000000000001502456746400207072../0000-0035.testustar00rootroot00000000000000librecast/test/tsan/0000-0036.test000077700000000000000000000000001502456746400207112../0000-0036.testustar00rootroot00000000000000librecast/test/tsan/0000-0037.test000077700000000000000000000000001502456746400207132../0000-0037.testustar00rootroot00000000000000librecast/test/tsan/0000-0038.test000077700000000000000000000000001502456746400207152../0000-0038.testustar00rootroot00000000000000librecast/test/tsan/0000-0039.test000077700000000000000000000000001502456746400207172../0000-0039.testustar00rootroot00000000000000librecast/test/tsan/0000-0040.test000077700000000000000000000000001502456746400206772../0000-0040.testustar00rootroot00000000000000librecast/test/tsan/0000-0041.test000077700000000000000000000000001502456746400207012../0000-0041.testustar00rootroot00000000000000librecast/test/tsan/0000-0042.test000077700000000000000000000000001502456746400207032../0000-0042.testustar00rootroot00000000000000librecast/test/tsan/0000-0043.test000077700000000000000000000000001502456746400207052../0000-0043.testustar00rootroot00000000000000librecast/test/tsan/0000-0044.test000077700000000000000000000000001502456746400207072../0000-0044.testustar00rootroot00000000000000librecast/test/tsan/0000-0045.test000077700000000000000000000000001502456746400207112../0000-0045.testustar00rootroot00000000000000librecast/test/tsan/0000-0046.test000077700000000000000000000000001502456746400207132../0000-0046.testustar00rootroot00000000000000librecast/test/tsan/0000-0047.test000077700000000000000000000000001502456746400207152../0000-0047.testustar00rootroot00000000000000librecast/test/tsan/0000-0048.test000077700000000000000000000000001502456746400207172../0000-0048.testustar00rootroot00000000000000librecast/test/tsan/0000-0049.test000077700000000000000000000000001502456746400207212../0000-0049.testustar00rootroot00000000000000librecast/test/tsan/0000-0050.test000077700000000000000000000000001502456746400207012../0000-0050.testustar00rootroot00000000000000librecast/test/tsan/0000-0051.test000077700000000000000000000000001502456746400207032../0000-0051.testustar00rootroot00000000000000librecast/test/tsan/0000-0052.test000077700000000000000000000000001502456746400207052../0000-0052.testustar00rootroot00000000000000librecast/test/tsan/0000-0053.test000077700000000000000000000000001502456746400207072../0000-0053.testustar00rootroot00000000000000librecast/test/tsan/0000-0054.test000077700000000000000000000000001502456746400207112../0000-0054.testustar00rootroot00000000000000librecast/test/tsan/0000-0055.test000077700000000000000000000000001502456746400207132../0000-0055.testustar00rootroot00000000000000librecast/test/tsan/0000-0056.test000077700000000000000000000000001502456746400207152../0000-0056.testustar00rootroot00000000000000librecast/test/tsan/0000-0057.test000077700000000000000000000000001502456746400207172../0000-0057.testustar00rootroot00000000000000librecast/test/tsan/0000-0058.test000077700000000000000000000000001502456746400207212../0000-0058.testustar00rootroot00000000000000librecast/test/tsan/0000-0059.test000077700000000000000000000000001502456746400207232../0000-0059.testustar00rootroot00000000000000librecast/test/tsan/0000-0060.test000077700000000000000000000000001502456746400222142test/enc/0000-0060.testustar00rootroot00000000000000librecast/test/tsan/0000-0061.test000077700000000000000000000000001502456746400207052../0000-0061.testustar00rootroot00000000000000librecast/test/tsan/0000-0064.test000077700000000000000000000000001502456746400207132../0000-0064.testustar00rootroot00000000000000librecast/test/tsan/0000-0100.test000077700000000000000000000000001502456746400206712../0000-0100.testustar00rootroot00000000000000librecast/test/tsan/0000-0101.test000077700000000000000000000000001502456746400206732../0000-0101.testustar00rootroot00000000000000librecast/test/tsan/0000-0110.test000077700000000000000000000000001502456746400206732../0000-0110.testustar00rootroot00000000000000librecast/test/tsan/0000-0111.test000077700000000000000000000000001502456746400206752../0000-0111.testustar00rootroot00000000000000librecast/test/tsan/0000-0112.test000077700000000000000000000000001502456746400206772../0000-0112.testustar00rootroot00000000000000librecast/test/tsan/0000-0113.test000077700000000000000000000000001502456746400207012../0000-0113.testustar00rootroot00000000000000librecast/test/tsan/0000-0114.test000077700000000000000000000000001502456746400207032../0000-0114.testustar00rootroot00000000000000librecast/test/tsan/0000-0115.test000077700000000000000000000000001502456746400207052../0000-0115.testustar00rootroot00000000000000librecast/test/tsan/0000-0116.test000077700000000000000000000000001502456746400207072../0000-0116.testustar00rootroot00000000000000librecast/test/tsan/0000-0117.test000077700000000000000000000000001502456746400207112../0000-0117.testustar00rootroot00000000000000librecast/test/tsan/0000-0118.test000077700000000000000000000000001502456746400207132../0000-0118.testustar00rootroot00000000000000librecast/test/tsan/0000-0119.test000077700000000000000000000000001502456746400207152../0000-0119.testustar00rootroot00000000000000librecast/test/tsan/0000-0120.test000077700000000000000000000000001502456746400206752../0000-0120.testustar00rootroot00000000000000librecast/test/tsan/0000-0121.test000077700000000000000000000000001502456746400206772../0000-0121.testustar00rootroot00000000000000librecast/test/tsan/0000-0139.test000077700000000000000000000000001502456746400207212../0000-0139.testustar00rootroot00000000000000librecast/test/tsan/0000-0140.test000077700000000000000000000000001502456746400207012../0000-0140.testustar00rootroot00000000000000librecast/test/tsan/0000-0142.test000077700000000000000000000000001502456746400207052../0000-0142.testustar00rootroot00000000000000librecast/test/tsan/0000-0190.test000077700000000000000000000000001502456746400207132../0000-0190.testustar00rootroot00000000000000librecast/test/valgrind.h000066400000000000000000014713751502456746400160230ustar00rootroot00000000000000/* -*- c -*- ---------------------------------------------------------------- Notice that the following BSD-style license applies to this one file (valgrind.h) only. The rest of Valgrind is licensed under the terms of the GNU General Public License, version 2, unless otherwise indicated. See the COPYING file in the source distribution for details. ---------------------------------------------------------------- This file is part of Valgrind, a dynamic binary instrumentation framework. Copyright (C) 2000-2017 Julian Seward. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 3. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 4. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------- Notice that the above BSD-style license applies to this one file (valgrind.h) only. The entire rest of Valgrind is licensed under the terms of the GNU General Public License, version 2. See the COPYING file in the source distribution for details. ---------------------------------------------------------------- */ /* This file is for inclusion into client (your!) code. You can use these macros to manipulate and query Valgrind's execution inside your own programs. The resulting executables will still run without Valgrind, just a little bit more slowly than they otherwise would, but otherwise unchanged. When not running on valgrind, each client request consumes very few (eg. 7) instructions, so the resulting performance loss is negligible unless you plan to execute client requests millions of times per second. Nevertheless, if that is still a problem, you can compile with the NVALGRIND symbol defined (gcc -DNVALGRIND) so that client requests are not even compiled in. */ #ifndef __VALGRIND_H #define __VALGRIND_H /* ------------------------------------------------------------------ */ /* VERSION NUMBER OF VALGRIND */ /* ------------------------------------------------------------------ */ /* Specify Valgrind's version number, so that user code can conditionally compile based on our version number. Note that these were introduced at version 3.6 and so do not exist in version 3.5 or earlier. The recommended way to use them to check for "version X.Y or later" is (eg) #if defined(__VALGRIND_MAJOR__) && defined(__VALGRIND_MINOR__) \ && (__VALGRIND_MAJOR__ > 3 \ || (__VALGRIND_MAJOR__ == 3 && __VALGRIND_MINOR__ >= 6)) */ #define __VALGRIND_MAJOR__ 3 #define __VALGRIND_MINOR__ 16 #include /* Nb: this file might be included in a file compiled with -ansi. So we can't use C++ style "//" comments nor the "asm" keyword (instead use "__asm__"). */ /* Derive some tags indicating what the target platform is. Note that in this file we're using the compiler's CPP symbols for identifying architectures, which are different to the ones we use within the rest of Valgrind. Note, __powerpc__ is active for both 32 and 64-bit PPC, whereas __powerpc64__ is only active for the latter (on Linux, that is). Misc note: how to find out what's predefined in gcc by default: gcc -Wp,-dM somefile.c */ #undef PLAT_x86_darwin #undef PLAT_amd64_darwin #undef PLAT_x86_win32 #undef PLAT_amd64_win64 #undef PLAT_x86_linux #undef PLAT_amd64_linux #undef PLAT_ppc32_linux #undef PLAT_ppc64be_linux #undef PLAT_ppc64le_linux #undef PLAT_arm_linux #undef PLAT_arm64_linux #undef PLAT_s390x_linux #undef PLAT_mips32_linux #undef PLAT_mips64_linux #undef PLAT_nanomips_linux #undef PLAT_x86_solaris #undef PLAT_amd64_solaris #if defined(__APPLE__) && defined(__i386__) # define PLAT_x86_darwin 1 #elif defined(__APPLE__) && defined(__x86_64__) # define PLAT_amd64_darwin 1 #elif (defined(__MINGW32__) && defined(__i386__)) \ || defined(__CYGWIN32__) \ || (defined(_WIN32) && defined(_M_IX86)) # define PLAT_x86_win32 1 #elif (defined(__MINGW32__) && defined(__x86_64__)) \ || (defined(_WIN32) && defined(_M_X64)) /* __MINGW32__ and _WIN32 are defined in 64 bit mode as well. */ # define PLAT_amd64_win64 1 #elif defined(__linux__) && defined(__i386__) # define PLAT_x86_linux 1 #elif defined(__linux__) && defined(__x86_64__) && !defined(__ILP32__) # define PLAT_amd64_linux 1 #elif defined(__linux__) && defined(__powerpc__) && !defined(__powerpc64__) # define PLAT_ppc32_linux 1 #elif defined(__linux__) && defined(__powerpc__) && defined(__powerpc64__) && _CALL_ELF != 2 /* Big Endian uses ELF version 1 */ # define PLAT_ppc64be_linux 1 #elif defined(__linux__) && defined(__powerpc__) && defined(__powerpc64__) && _CALL_ELF == 2 /* Little Endian uses ELF version 2 */ # define PLAT_ppc64le_linux 1 #elif defined(__linux__) && defined(__arm__) && !defined(__aarch64__) # define PLAT_arm_linux 1 #elif defined(__linux__) && defined(__aarch64__) && !defined(__arm__) # define PLAT_arm64_linux 1 #elif defined(__linux__) && defined(__s390__) && defined(__s390x__) # define PLAT_s390x_linux 1 #elif defined(__linux__) && defined(__mips__) && (__mips==64) # define PLAT_mips64_linux 1 #elif defined(__linux__) && defined(__mips__) && (__mips==32) # define PLAT_mips32_linux 1 #elif defined(__linux__) && defined(__nanomips__) # define PLAT_nanomips_linux 1 #elif defined(__sun) && defined(__i386__) # define PLAT_x86_solaris 1 #elif defined(__sun) && defined(__x86_64__) # define PLAT_amd64_solaris 1 #else /* If we're not compiling for our target platform, don't generate any inline asms. */ # if !defined(NVALGRIND) # define NVALGRIND 1 # endif #endif /* ------------------------------------------------------------------ */ /* ARCHITECTURE SPECIFICS for SPECIAL INSTRUCTIONS. There is nothing */ /* in here of use to end-users -- skip to the next section. */ /* ------------------------------------------------------------------ */ /* * VALGRIND_DO_CLIENT_REQUEST(): a statement that invokes a Valgrind client * request. Accepts both pointers and integers as arguments. * * VALGRIND_DO_CLIENT_REQUEST_STMT(): a statement that invokes a Valgrind * client request that does not return a value. * VALGRIND_DO_CLIENT_REQUEST_EXPR(): a C expression that invokes a Valgrind * client request and whose value equals the client request result. Accepts * both pointers and integers as arguments. Note that such calls are not * necessarily pure functions -- they may have side effects. */ #define VALGRIND_DO_CLIENT_REQUEST(_zzq_rlval, _zzq_default, \ _zzq_request, _zzq_arg1, _zzq_arg2, \ _zzq_arg3, _zzq_arg4, _zzq_arg5) \ do { (_zzq_rlval) = VALGRIND_DO_CLIENT_REQUEST_EXPR((_zzq_default), \ (_zzq_request), (_zzq_arg1), (_zzq_arg2), \ (_zzq_arg3), (_zzq_arg4), (_zzq_arg5)); } while (0) #define VALGRIND_DO_CLIENT_REQUEST_STMT(_zzq_request, _zzq_arg1, \ _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ do { (void) VALGRIND_DO_CLIENT_REQUEST_EXPR(0, \ (_zzq_request), (_zzq_arg1), (_zzq_arg2), \ (_zzq_arg3), (_zzq_arg4), (_zzq_arg5)); } while (0) #if defined(NVALGRIND) /* Define NVALGRIND to completely remove the Valgrind magic sequence from the compiled code (analogous to NDEBUG's effects on assert()) */ #define VALGRIND_DO_CLIENT_REQUEST_EXPR( \ _zzq_default, _zzq_request, \ _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ (_zzq_default) #else /* ! NVALGRIND */ /* The following defines the magic code sequences which the JITter spots and handles magically. Don't look too closely at them as they will rot your brain. The assembly code sequences for all architectures is in this one file. This is because this file must be stand-alone, and we don't want to have multiple files. For VALGRIND_DO_CLIENT_REQUEST, we must ensure that the default value gets put in the return slot, so that everything works when this is executed not under Valgrind. Args are passed in a memory block, and so there's no intrinsic limit to the number that could be passed, but it's currently five. The macro args are: _zzq_rlval result lvalue _zzq_default default value (result returned when running on real CPU) _zzq_request request code _zzq_arg1..5 request params The other two macros are used to support function wrapping, and are a lot simpler. VALGRIND_GET_NR_CONTEXT returns the value of the guest's NRADDR pseudo-register and whatever other information is needed to safely run the call original from the wrapper: on ppc64-linux, the R2 value at the divert point is also needed. This information is abstracted into a user-visible type, OrigFn. VALGRIND_CALL_NOREDIR_* behaves the same as the following on the guest, but guarantees that the branch instruction will not be redirected: x86: call *%eax, amd64: call *%rax, ppc32/ppc64: branch-and-link-to-r11. VALGRIND_CALL_NOREDIR is just text, not a complete inline asm, since it needs to be combined with more magic inline asm stuff to be useful. */ /* ----------------- x86-{linux,darwin,solaris} ---------------- */ #if defined(PLAT_x86_linux) || defined(PLAT_x86_darwin) \ || (defined(PLAT_x86_win32) && defined(__GNUC__)) \ || defined(PLAT_x86_solaris) typedef struct { unsigned int nraddr; /* where's the code? */ } OrigFn; #define __SPECIAL_INSTRUCTION_PREAMBLE \ "roll $3, %%edi ; roll $13, %%edi\n\t" \ "roll $29, %%edi ; roll $19, %%edi\n\t" #define VALGRIND_DO_CLIENT_REQUEST_EXPR( \ _zzq_default, _zzq_request, \ _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ __extension__ \ ({volatile unsigned int _zzq_args[6]; \ volatile unsigned int _zzq_result; \ _zzq_args[0] = (unsigned int)(_zzq_request); \ _zzq_args[1] = (unsigned int)(_zzq_arg1); \ _zzq_args[2] = (unsigned int)(_zzq_arg2); \ _zzq_args[3] = (unsigned int)(_zzq_arg3); \ _zzq_args[4] = (unsigned int)(_zzq_arg4); \ _zzq_args[5] = (unsigned int)(_zzq_arg5); \ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ /* %EDX = client_request ( %EAX ) */ \ "xchgl %%ebx,%%ebx" \ : "=d" (_zzq_result) \ : "a" (&_zzq_args[0]), "0" (_zzq_default) \ : "cc", "memory" \ ); \ _zzq_result; \ }) #define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \ { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \ volatile unsigned int __addr; \ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ /* %EAX = guest_NRADDR */ \ "xchgl %%ecx,%%ecx" \ : "=a" (__addr) \ : \ : "cc", "memory" \ ); \ _zzq_orig->nraddr = __addr; \ } #define VALGRIND_CALL_NOREDIR_EAX \ __SPECIAL_INSTRUCTION_PREAMBLE \ /* call-noredir *%EAX */ \ "xchgl %%edx,%%edx\n\t" #define VALGRIND_VEX_INJECT_IR() \ do { \ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ "xchgl %%edi,%%edi\n\t" \ : : : "cc", "memory" \ ); \ } while (0) #endif /* PLAT_x86_linux || PLAT_x86_darwin || (PLAT_x86_win32 && __GNUC__) || PLAT_x86_solaris */ /* ------------------------- x86-Win32 ------------------------- */ #if defined(PLAT_x86_win32) && !defined(__GNUC__) typedef struct { unsigned int nraddr; /* where's the code? */ } OrigFn; #if defined(_MSC_VER) #define __SPECIAL_INSTRUCTION_PREAMBLE \ __asm rol edi, 3 __asm rol edi, 13 \ __asm rol edi, 29 __asm rol edi, 19 #define VALGRIND_DO_CLIENT_REQUEST_EXPR( \ _zzq_default, _zzq_request, \ _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ valgrind_do_client_request_expr((uintptr_t)(_zzq_default), \ (uintptr_t)(_zzq_request), (uintptr_t)(_zzq_arg1), \ (uintptr_t)(_zzq_arg2), (uintptr_t)(_zzq_arg3), \ (uintptr_t)(_zzq_arg4), (uintptr_t)(_zzq_arg5)) static __inline uintptr_t valgrind_do_client_request_expr(uintptr_t _zzq_default, uintptr_t _zzq_request, uintptr_t _zzq_arg1, uintptr_t _zzq_arg2, uintptr_t _zzq_arg3, uintptr_t _zzq_arg4, uintptr_t _zzq_arg5) { volatile uintptr_t _zzq_args[6]; volatile unsigned int _zzq_result; _zzq_args[0] = (uintptr_t)(_zzq_request); _zzq_args[1] = (uintptr_t)(_zzq_arg1); _zzq_args[2] = (uintptr_t)(_zzq_arg2); _zzq_args[3] = (uintptr_t)(_zzq_arg3); _zzq_args[4] = (uintptr_t)(_zzq_arg4); _zzq_args[5] = (uintptr_t)(_zzq_arg5); __asm { __asm lea eax, _zzq_args __asm mov edx, _zzq_default __SPECIAL_INSTRUCTION_PREAMBLE /* %EDX = client_request ( %EAX ) */ __asm xchg ebx,ebx __asm mov _zzq_result, edx } return _zzq_result; } #define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \ { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \ volatile unsigned int __addr; \ __asm { __SPECIAL_INSTRUCTION_PREAMBLE \ /* %EAX = guest_NRADDR */ \ __asm xchg ecx,ecx \ __asm mov __addr, eax \ } \ _zzq_orig->nraddr = __addr; \ } #define VALGRIND_CALL_NOREDIR_EAX ERROR #define VALGRIND_VEX_INJECT_IR() \ do { \ __asm { __SPECIAL_INSTRUCTION_PREAMBLE \ __asm xchg edi,edi \ } \ } while (0) #else #error Unsupported compiler. #endif #endif /* PLAT_x86_win32 */ /* ----------------- amd64-{linux,darwin,solaris} --------------- */ #if defined(PLAT_amd64_linux) || defined(PLAT_amd64_darwin) \ || defined(PLAT_amd64_solaris) \ || (defined(PLAT_amd64_win64) && defined(__GNUC__)) typedef struct { unsigned long int nraddr; /* where's the code? */ } OrigFn; #define __SPECIAL_INSTRUCTION_PREAMBLE \ "rolq $3, %%rdi ; rolq $13, %%rdi\n\t" \ "rolq $61, %%rdi ; rolq $51, %%rdi\n\t" #define VALGRIND_DO_CLIENT_REQUEST_EXPR( \ _zzq_default, _zzq_request, \ _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ __extension__ \ ({ volatile unsigned long int _zzq_args[6]; \ volatile unsigned long int _zzq_result; \ _zzq_args[0] = (unsigned long int)(_zzq_request); \ _zzq_args[1] = (unsigned long int)(_zzq_arg1); \ _zzq_args[2] = (unsigned long int)(_zzq_arg2); \ _zzq_args[3] = (unsigned long int)(_zzq_arg3); \ _zzq_args[4] = (unsigned long int)(_zzq_arg4); \ _zzq_args[5] = (unsigned long int)(_zzq_arg5); \ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ /* %RDX = client_request ( %RAX ) */ \ "xchgq %%rbx,%%rbx" \ : "=d" (_zzq_result) \ : "a" (&_zzq_args[0]), "0" (_zzq_default) \ : "cc", "memory" \ ); \ _zzq_result; \ }) #define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \ { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \ volatile unsigned long int __addr; \ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ /* %RAX = guest_NRADDR */ \ "xchgq %%rcx,%%rcx" \ : "=a" (__addr) \ : \ : "cc", "memory" \ ); \ _zzq_orig->nraddr = __addr; \ } #define VALGRIND_CALL_NOREDIR_RAX \ __SPECIAL_INSTRUCTION_PREAMBLE \ /* call-noredir *%RAX */ \ "xchgq %%rdx,%%rdx\n\t" #define VALGRIND_VEX_INJECT_IR() \ do { \ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ "xchgq %%rdi,%%rdi\n\t" \ : : : "cc", "memory" \ ); \ } while (0) #endif /* PLAT_amd64_linux || PLAT_amd64_darwin || PLAT_amd64_solaris */ /* ------------------------- amd64-Win64 ------------------------- */ #if defined(PLAT_amd64_win64) && !defined(__GNUC__) #error Unsupported compiler. #endif /* PLAT_amd64_win64 */ /* ------------------------ ppc32-linux ------------------------ */ #if defined(PLAT_ppc32_linux) typedef struct { unsigned int nraddr; /* where's the code? */ } OrigFn; #define __SPECIAL_INSTRUCTION_PREAMBLE \ "rlwinm 0,0,3,0,31 ; rlwinm 0,0,13,0,31\n\t" \ "rlwinm 0,0,29,0,31 ; rlwinm 0,0,19,0,31\n\t" #define VALGRIND_DO_CLIENT_REQUEST_EXPR( \ _zzq_default, _zzq_request, \ _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ \ __extension__ \ ({ unsigned int _zzq_args[6]; \ unsigned int _zzq_result; \ unsigned int* _zzq_ptr; \ _zzq_args[0] = (unsigned int)(_zzq_request); \ _zzq_args[1] = (unsigned int)(_zzq_arg1); \ _zzq_args[2] = (unsigned int)(_zzq_arg2); \ _zzq_args[3] = (unsigned int)(_zzq_arg3); \ _zzq_args[4] = (unsigned int)(_zzq_arg4); \ _zzq_args[5] = (unsigned int)(_zzq_arg5); \ _zzq_ptr = _zzq_args; \ __asm__ volatile("mr 3,%1\n\t" /*default*/ \ "mr 4,%2\n\t" /*ptr*/ \ __SPECIAL_INSTRUCTION_PREAMBLE \ /* %R3 = client_request ( %R4 ) */ \ "or 1,1,1\n\t" \ "mr %0,3" /*result*/ \ : "=b" (_zzq_result) \ : "b" (_zzq_default), "b" (_zzq_ptr) \ : "cc", "memory", "r3", "r4"); \ _zzq_result; \ }) #define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \ { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \ unsigned int __addr; \ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ /* %R3 = guest_NRADDR */ \ "or 2,2,2\n\t" \ "mr %0,3" \ : "=b" (__addr) \ : \ : "cc", "memory", "r3" \ ); \ _zzq_orig->nraddr = __addr; \ } #define VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ __SPECIAL_INSTRUCTION_PREAMBLE \ /* branch-and-link-to-noredir *%R11 */ \ "or 3,3,3\n\t" #define VALGRIND_VEX_INJECT_IR() \ do { \ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ "or 5,5,5\n\t" \ ); \ } while (0) #endif /* PLAT_ppc32_linux */ /* ------------------------ ppc64-linux ------------------------ */ #if defined(PLAT_ppc64be_linux) typedef struct { unsigned long int nraddr; /* where's the code? */ unsigned long int r2; /* what tocptr do we need? */ } OrigFn; #define __SPECIAL_INSTRUCTION_PREAMBLE \ "rotldi 0,0,3 ; rotldi 0,0,13\n\t" \ "rotldi 0,0,61 ; rotldi 0,0,51\n\t" #define VALGRIND_DO_CLIENT_REQUEST_EXPR( \ _zzq_default, _zzq_request, \ _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ \ __extension__ \ ({ unsigned long int _zzq_args[6]; \ unsigned long int _zzq_result; \ unsigned long int* _zzq_ptr; \ _zzq_args[0] = (unsigned long int)(_zzq_request); \ _zzq_args[1] = (unsigned long int)(_zzq_arg1); \ _zzq_args[2] = (unsigned long int)(_zzq_arg2); \ _zzq_args[3] = (unsigned long int)(_zzq_arg3); \ _zzq_args[4] = (unsigned long int)(_zzq_arg4); \ _zzq_args[5] = (unsigned long int)(_zzq_arg5); \ _zzq_ptr = _zzq_args; \ __asm__ volatile("mr 3,%1\n\t" /*default*/ \ "mr 4,%2\n\t" /*ptr*/ \ __SPECIAL_INSTRUCTION_PREAMBLE \ /* %R3 = client_request ( %R4 ) */ \ "or 1,1,1\n\t" \ "mr %0,3" /*result*/ \ : "=b" (_zzq_result) \ : "b" (_zzq_default), "b" (_zzq_ptr) \ : "cc", "memory", "r3", "r4"); \ _zzq_result; \ }) #define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \ { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \ unsigned long int __addr; \ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ /* %R3 = guest_NRADDR */ \ "or 2,2,2\n\t" \ "mr %0,3" \ : "=b" (__addr) \ : \ : "cc", "memory", "r3" \ ); \ _zzq_orig->nraddr = __addr; \ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ /* %R3 = guest_NRADDR_GPR2 */ \ "or 4,4,4\n\t" \ "mr %0,3" \ : "=b" (__addr) \ : \ : "cc", "memory", "r3" \ ); \ _zzq_orig->r2 = __addr; \ } #define VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ __SPECIAL_INSTRUCTION_PREAMBLE \ /* branch-and-link-to-noredir *%R11 */ \ "or 3,3,3\n\t" #define VALGRIND_VEX_INJECT_IR() \ do { \ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ "or 5,5,5\n\t" \ ); \ } while (0) #endif /* PLAT_ppc64be_linux */ #if defined(PLAT_ppc64le_linux) typedef struct { unsigned long int nraddr; /* where's the code? */ unsigned long int r2; /* what tocptr do we need? */ } OrigFn; #define __SPECIAL_INSTRUCTION_PREAMBLE \ "rotldi 0,0,3 ; rotldi 0,0,13\n\t" \ "rotldi 0,0,61 ; rotldi 0,0,51\n\t" #define VALGRIND_DO_CLIENT_REQUEST_EXPR( \ _zzq_default, _zzq_request, \ _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ \ __extension__ \ ({ unsigned long int _zzq_args[6]; \ unsigned long int _zzq_result; \ unsigned long int* _zzq_ptr; \ _zzq_args[0] = (unsigned long int)(_zzq_request); \ _zzq_args[1] = (unsigned long int)(_zzq_arg1); \ _zzq_args[2] = (unsigned long int)(_zzq_arg2); \ _zzq_args[3] = (unsigned long int)(_zzq_arg3); \ _zzq_args[4] = (unsigned long int)(_zzq_arg4); \ _zzq_args[5] = (unsigned long int)(_zzq_arg5); \ _zzq_ptr = _zzq_args; \ __asm__ volatile("mr 3,%1\n\t" /*default*/ \ "mr 4,%2\n\t" /*ptr*/ \ __SPECIAL_INSTRUCTION_PREAMBLE \ /* %R3 = client_request ( %R4 ) */ \ "or 1,1,1\n\t" \ "mr %0,3" /*result*/ \ : "=b" (_zzq_result) \ : "b" (_zzq_default), "b" (_zzq_ptr) \ : "cc", "memory", "r3", "r4"); \ _zzq_result; \ }) #define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \ { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \ unsigned long int __addr; \ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ /* %R3 = guest_NRADDR */ \ "or 2,2,2\n\t" \ "mr %0,3" \ : "=b" (__addr) \ : \ : "cc", "memory", "r3" \ ); \ _zzq_orig->nraddr = __addr; \ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ /* %R3 = guest_NRADDR_GPR2 */ \ "or 4,4,4\n\t" \ "mr %0,3" \ : "=b" (__addr) \ : \ : "cc", "memory", "r3" \ ); \ _zzq_orig->r2 = __addr; \ } #define VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R12 \ __SPECIAL_INSTRUCTION_PREAMBLE \ /* branch-and-link-to-noredir *%R12 */ \ "or 3,3,3\n\t" #define VALGRIND_VEX_INJECT_IR() \ do { \ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ "or 5,5,5\n\t" \ ); \ } while (0) #endif /* PLAT_ppc64le_linux */ /* ------------------------- arm-linux ------------------------- */ #if defined(PLAT_arm_linux) typedef struct { unsigned int nraddr; /* where's the code? */ } OrigFn; #define __SPECIAL_INSTRUCTION_PREAMBLE \ "mov r12, r12, ror #3 ; mov r12, r12, ror #13 \n\t" \ "mov r12, r12, ror #29 ; mov r12, r12, ror #19 \n\t" #define VALGRIND_DO_CLIENT_REQUEST_EXPR( \ _zzq_default, _zzq_request, \ _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ \ __extension__ \ ({volatile unsigned int _zzq_args[6]; \ volatile unsigned int _zzq_result; \ _zzq_args[0] = (unsigned int)(_zzq_request); \ _zzq_args[1] = (unsigned int)(_zzq_arg1); \ _zzq_args[2] = (unsigned int)(_zzq_arg2); \ _zzq_args[3] = (unsigned int)(_zzq_arg3); \ _zzq_args[4] = (unsigned int)(_zzq_arg4); \ _zzq_args[5] = (unsigned int)(_zzq_arg5); \ __asm__ volatile("mov r3, %1\n\t" /*default*/ \ "mov r4, %2\n\t" /*ptr*/ \ __SPECIAL_INSTRUCTION_PREAMBLE \ /* R3 = client_request ( R4 ) */ \ "orr r10, r10, r10\n\t" \ "mov %0, r3" /*result*/ \ : "=r" (_zzq_result) \ : "r" (_zzq_default), "r" (&_zzq_args[0]) \ : "cc","memory", "r3", "r4"); \ _zzq_result; \ }) #define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \ { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \ unsigned int __addr; \ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ /* R3 = guest_NRADDR */ \ "orr r11, r11, r11\n\t" \ "mov %0, r3" \ : "=r" (__addr) \ : \ : "cc", "memory", "r3" \ ); \ _zzq_orig->nraddr = __addr; \ } #define VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ __SPECIAL_INSTRUCTION_PREAMBLE \ /* branch-and-link-to-noredir *%R4 */ \ "orr r12, r12, r12\n\t" #define VALGRIND_VEX_INJECT_IR() \ do { \ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ "orr r9, r9, r9\n\t" \ : : : "cc", "memory" \ ); \ } while (0) #endif /* PLAT_arm_linux */ /* ------------------------ arm64-linux ------------------------- */ #if defined(PLAT_arm64_linux) typedef struct { unsigned long int nraddr; /* where's the code? */ } OrigFn; #define __SPECIAL_INSTRUCTION_PREAMBLE \ "ror x12, x12, #3 ; ror x12, x12, #13 \n\t" \ "ror x12, x12, #51 ; ror x12, x12, #61 \n\t" #define VALGRIND_DO_CLIENT_REQUEST_EXPR( \ _zzq_default, _zzq_request, \ _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ \ __extension__ \ ({volatile unsigned long int _zzq_args[6]; \ volatile unsigned long int _zzq_result; \ _zzq_args[0] = (unsigned long int)(_zzq_request); \ _zzq_args[1] = (unsigned long int)(_zzq_arg1); \ _zzq_args[2] = (unsigned long int)(_zzq_arg2); \ _zzq_args[3] = (unsigned long int)(_zzq_arg3); \ _zzq_args[4] = (unsigned long int)(_zzq_arg4); \ _zzq_args[5] = (unsigned long int)(_zzq_arg5); \ __asm__ volatile("mov x3, %1\n\t" /*default*/ \ "mov x4, %2\n\t" /*ptr*/ \ __SPECIAL_INSTRUCTION_PREAMBLE \ /* X3 = client_request ( X4 ) */ \ "orr x10, x10, x10\n\t" \ "mov %0, x3" /*result*/ \ : "=r" (_zzq_result) \ : "r" ((unsigned long int)(_zzq_default)), \ "r" (&_zzq_args[0]) \ : "cc","memory", "x3", "x4"); \ _zzq_result; \ }) #define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \ { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \ unsigned long int __addr; \ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ /* X3 = guest_NRADDR */ \ "orr x11, x11, x11\n\t" \ "mov %0, x3" \ : "=r" (__addr) \ : \ : "cc", "memory", "x3" \ ); \ _zzq_orig->nraddr = __addr; \ } #define VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_X8 \ __SPECIAL_INSTRUCTION_PREAMBLE \ /* branch-and-link-to-noredir X8 */ \ "orr x12, x12, x12\n\t" #define VALGRIND_VEX_INJECT_IR() \ do { \ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ "orr x9, x9, x9\n\t" \ : : : "cc", "memory" \ ); \ } while (0) #endif /* PLAT_arm64_linux */ /* ------------------------ s390x-linux ------------------------ */ #if defined(PLAT_s390x_linux) typedef struct { unsigned long int nraddr; /* where's the code? */ } OrigFn; /* __SPECIAL_INSTRUCTION_PREAMBLE will be used to identify Valgrind specific * code. This detection is implemented in platform specific toIR.c * (e.g. VEX/priv/guest_s390_decoder.c). */ #define __SPECIAL_INSTRUCTION_PREAMBLE \ "lr 15,15\n\t" \ "lr 1,1\n\t" \ "lr 2,2\n\t" \ "lr 3,3\n\t" #define __CLIENT_REQUEST_CODE "lr 2,2\n\t" #define __GET_NR_CONTEXT_CODE "lr 3,3\n\t" #define __CALL_NO_REDIR_CODE "lr 4,4\n\t" #define __VEX_INJECT_IR_CODE "lr 5,5\n\t" #define VALGRIND_DO_CLIENT_REQUEST_EXPR( \ _zzq_default, _zzq_request, \ _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ __extension__ \ ({volatile unsigned long int _zzq_args[6]; \ volatile unsigned long int _zzq_result; \ _zzq_args[0] = (unsigned long int)(_zzq_request); \ _zzq_args[1] = (unsigned long int)(_zzq_arg1); \ _zzq_args[2] = (unsigned long int)(_zzq_arg2); \ _zzq_args[3] = (unsigned long int)(_zzq_arg3); \ _zzq_args[4] = (unsigned long int)(_zzq_arg4); \ _zzq_args[5] = (unsigned long int)(_zzq_arg5); \ __asm__ volatile(/* r2 = args */ \ "lgr 2,%1\n\t" \ /* r3 = default */ \ "lgr 3,%2\n\t" \ __SPECIAL_INSTRUCTION_PREAMBLE \ __CLIENT_REQUEST_CODE \ /* results = r3 */ \ "lgr %0, 3\n\t" \ : "=d" (_zzq_result) \ : "a" (&_zzq_args[0]), "0" (_zzq_default) \ : "cc", "2", "3", "memory" \ ); \ _zzq_result; \ }) #define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \ { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \ volatile unsigned long int __addr; \ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ __GET_NR_CONTEXT_CODE \ "lgr %0, 3\n\t" \ : "=a" (__addr) \ : \ : "cc", "3", "memory" \ ); \ _zzq_orig->nraddr = __addr; \ } #define VALGRIND_CALL_NOREDIR_R1 \ __SPECIAL_INSTRUCTION_PREAMBLE \ __CALL_NO_REDIR_CODE #define VALGRIND_VEX_INJECT_IR() \ do { \ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ __VEX_INJECT_IR_CODE); \ } while (0) #endif /* PLAT_s390x_linux */ /* ------------------------- mips32-linux ---------------- */ #if defined(PLAT_mips32_linux) typedef struct { unsigned int nraddr; /* where's the code? */ } OrigFn; /* .word 0x342 * .word 0x742 * .word 0xC2 * .word 0x4C2*/ #define __SPECIAL_INSTRUCTION_PREAMBLE \ "srl $0, $0, 13\n\t" \ "srl $0, $0, 29\n\t" \ "srl $0, $0, 3\n\t" \ "srl $0, $0, 19\n\t" #define VALGRIND_DO_CLIENT_REQUEST_EXPR( \ _zzq_default, _zzq_request, \ _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ __extension__ \ ({ volatile unsigned int _zzq_args[6]; \ volatile unsigned int _zzq_result; \ _zzq_args[0] = (unsigned int)(_zzq_request); \ _zzq_args[1] = (unsigned int)(_zzq_arg1); \ _zzq_args[2] = (unsigned int)(_zzq_arg2); \ _zzq_args[3] = (unsigned int)(_zzq_arg3); \ _zzq_args[4] = (unsigned int)(_zzq_arg4); \ _zzq_args[5] = (unsigned int)(_zzq_arg5); \ __asm__ volatile("move $11, %1\n\t" /*default*/ \ "move $12, %2\n\t" /*ptr*/ \ __SPECIAL_INSTRUCTION_PREAMBLE \ /* T3 = client_request ( T4 ) */ \ "or $13, $13, $13\n\t" \ "move %0, $11\n\t" /*result*/ \ : "=r" (_zzq_result) \ : "r" (_zzq_default), "r" (&_zzq_args[0]) \ : "$11", "$12", "memory"); \ _zzq_result; \ }) #define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \ { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \ volatile unsigned int __addr; \ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ /* %t9 = guest_NRADDR */ \ "or $14, $14, $14\n\t" \ "move %0, $11" /*result*/ \ : "=r" (__addr) \ : \ : "$11" \ ); \ _zzq_orig->nraddr = __addr; \ } #define VALGRIND_CALL_NOREDIR_T9 \ __SPECIAL_INSTRUCTION_PREAMBLE \ /* call-noredir *%t9 */ \ "or $15, $15, $15\n\t" #define VALGRIND_VEX_INJECT_IR() \ do { \ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ "or $11, $11, $11\n\t" \ ); \ } while (0) #endif /* PLAT_mips32_linux */ /* ------------------------- mips64-linux ---------------- */ #if defined(PLAT_mips64_linux) typedef struct { unsigned long nraddr; /* where's the code? */ } OrigFn; /* dsll $0,$0, 3 * dsll $0,$0, 13 * dsll $0,$0, 29 * dsll $0,$0, 19*/ #define __SPECIAL_INSTRUCTION_PREAMBLE \ "dsll $0,$0, 3 ; dsll $0,$0,13\n\t" \ "dsll $0,$0,29 ; dsll $0,$0,19\n\t" #define VALGRIND_DO_CLIENT_REQUEST_EXPR( \ _zzq_default, _zzq_request, \ _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ __extension__ \ ({ volatile unsigned long int _zzq_args[6]; \ volatile unsigned long int _zzq_result; \ _zzq_args[0] = (unsigned long int)(_zzq_request); \ _zzq_args[1] = (unsigned long int)(_zzq_arg1); \ _zzq_args[2] = (unsigned long int)(_zzq_arg2); \ _zzq_args[3] = (unsigned long int)(_zzq_arg3); \ _zzq_args[4] = (unsigned long int)(_zzq_arg4); \ _zzq_args[5] = (unsigned long int)(_zzq_arg5); \ __asm__ volatile("move $11, %1\n\t" /*default*/ \ "move $12, %2\n\t" /*ptr*/ \ __SPECIAL_INSTRUCTION_PREAMBLE \ /* $11 = client_request ( $12 ) */ \ "or $13, $13, $13\n\t" \ "move %0, $11\n\t" /*result*/ \ : "=r" (_zzq_result) \ : "r" (_zzq_default), "r" (&_zzq_args[0]) \ : "$11", "$12", "memory"); \ _zzq_result; \ }) #define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \ { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \ volatile unsigned long int __addr; \ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ /* $11 = guest_NRADDR */ \ "or $14, $14, $14\n\t" \ "move %0, $11" /*result*/ \ : "=r" (__addr) \ : \ : "$11"); \ _zzq_orig->nraddr = __addr; \ } #define VALGRIND_CALL_NOREDIR_T9 \ __SPECIAL_INSTRUCTION_PREAMBLE \ /* call-noredir $25 */ \ "or $15, $15, $15\n\t" #define VALGRIND_VEX_INJECT_IR() \ do { \ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ "or $11, $11, $11\n\t" \ ); \ } while (0) #endif /* PLAT_mips64_linux */ #if defined(PLAT_nanomips_linux) typedef struct { unsigned int nraddr; /* where's the code? */ } OrigFn; /* 8000 c04d srl zero, zero, 13 8000 c05d srl zero, zero, 29 8000 c043 srl zero, zero, 3 8000 c053 srl zero, zero, 19 */ #define __SPECIAL_INSTRUCTION_PREAMBLE "srl[32] $zero, $zero, 13 \n\t" \ "srl[32] $zero, $zero, 29 \n\t" \ "srl[32] $zero, $zero, 3 \n\t" \ "srl[32] $zero, $zero, 19 \n\t" #define VALGRIND_DO_CLIENT_REQUEST_EXPR( \ _zzq_default, _zzq_request, \ _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ __extension__ \ ({ volatile unsigned int _zzq_args[6]; \ volatile unsigned int _zzq_result; \ _zzq_args[0] = (unsigned int)(_zzq_request); \ _zzq_args[1] = (unsigned int)(_zzq_arg1); \ _zzq_args[2] = (unsigned int)(_zzq_arg2); \ _zzq_args[3] = (unsigned int)(_zzq_arg3); \ _zzq_args[4] = (unsigned int)(_zzq_arg4); \ _zzq_args[5] = (unsigned int)(_zzq_arg5); \ __asm__ volatile("move $a7, %1\n\t" /* default */ \ "move $t0, %2\n\t" /* ptr */ \ __SPECIAL_INSTRUCTION_PREAMBLE \ /* $a7 = client_request( $t0 ) */ \ "or[32] $t0, $t0, $t0\n\t" \ "move %0, $a7\n\t" /* result */ \ : "=r" (_zzq_result) \ : "r" (_zzq_default), "r" (&_zzq_args[0]) \ : "$a7", "$t0", "memory"); \ _zzq_result; \ }) #define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \ { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \ volatile unsigned long int __addr; \ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ /* $a7 = guest_NRADDR */ \ "or[32] $t1, $t1, $t1\n\t" \ "move %0, $a7" /*result*/ \ : "=r" (__addr) \ : \ : "$a7"); \ _zzq_orig->nraddr = __addr; \ } #define VALGRIND_CALL_NOREDIR_T9 \ __SPECIAL_INSTRUCTION_PREAMBLE \ /* call-noredir $25 */ \ "or[32] $t2, $t2, $t2\n\t" #define VALGRIND_VEX_INJECT_IR() \ do { \ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ "or[32] $t3, $t3, $t3\n\t" \ ); \ } while (0) #endif /* Insert assembly code for other platforms here... */ #endif /* NVALGRIND */ /* ------------------------------------------------------------------ */ /* PLATFORM SPECIFICS for FUNCTION WRAPPING. This is all very */ /* ugly. It's the least-worst tradeoff I can think of. */ /* ------------------------------------------------------------------ */ /* This section defines magic (a.k.a appalling-hack) macros for doing guaranteed-no-redirection macros, so as to get from function wrappers to the functions they are wrapping. The whole point is to construct standard call sequences, but to do the call itself with a special no-redirect call pseudo-instruction that the JIT understands and handles specially. This section is long and repetitious, and I can't see a way to make it shorter. The naming scheme is as follows: CALL_FN_{W,v}_{v,W,WW,WWW,WWWW,5W,6W,7W,etc} 'W' stands for "word" and 'v' for "void". Hence there are different macros for calling arity 0, 1, 2, 3, 4, etc, functions, and for each, the possibility of returning a word-typed result, or no result. */ /* Use these to write the name of your wrapper. NOTE: duplicates VG_WRAP_FUNCTION_Z{U,Z} in pub_tool_redir.h. NOTE also: inserts the default behaviour equivalance class tag "0000" into the name. See pub_tool_redir.h for details -- normally you don't need to think about this, though. */ /* Use an extra level of macroisation so as to ensure the soname/fnname args are fully macro-expanded before pasting them together. */ #define VG_CONCAT4(_aa,_bb,_cc,_dd) _aa##_bb##_cc##_dd #define I_WRAP_SONAME_FNNAME_ZU(soname,fnname) \ VG_CONCAT4(_vgw00000ZU_,soname,_,fnname) #define I_WRAP_SONAME_FNNAME_ZZ(soname,fnname) \ VG_CONCAT4(_vgw00000ZZ_,soname,_,fnname) /* Use this macro from within a wrapper function to collect the context (address and possibly other info) of the original function. Once you have that you can then use it in one of the CALL_FN_ macros. The type of the argument _lval is OrigFn. */ #define VALGRIND_GET_ORIG_FN(_lval) VALGRIND_GET_NR_CONTEXT(_lval) /* Also provide end-user facilities for function replacement, rather than wrapping. A replacement function differs from a wrapper in that it has no way to get hold of the original function being called, and hence no way to call onwards to it. In a replacement function, VALGRIND_GET_ORIG_FN always returns zero. */ #define I_REPLACE_SONAME_FNNAME_ZU(soname,fnname) \ VG_CONCAT4(_vgr00000ZU_,soname,_,fnname) #define I_REPLACE_SONAME_FNNAME_ZZ(soname,fnname) \ VG_CONCAT4(_vgr00000ZZ_,soname,_,fnname) /* Derivatives of the main macros below, for calling functions returning void. */ #define CALL_FN_v_v(fnptr) \ do { volatile unsigned long _junk; \ CALL_FN_W_v(_junk,fnptr); } while (0) #define CALL_FN_v_W(fnptr, arg1) \ do { volatile unsigned long _junk; \ CALL_FN_W_W(_junk,fnptr,arg1); } while (0) #define CALL_FN_v_WW(fnptr, arg1,arg2) \ do { volatile unsigned long _junk; \ CALL_FN_W_WW(_junk,fnptr,arg1,arg2); } while (0) #define CALL_FN_v_WWW(fnptr, arg1,arg2,arg3) \ do { volatile unsigned long _junk; \ CALL_FN_W_WWW(_junk,fnptr,arg1,arg2,arg3); } while (0) #define CALL_FN_v_WWWW(fnptr, arg1,arg2,arg3,arg4) \ do { volatile unsigned long _junk; \ CALL_FN_W_WWWW(_junk,fnptr,arg1,arg2,arg3,arg4); } while (0) #define CALL_FN_v_5W(fnptr, arg1,arg2,arg3,arg4,arg5) \ do { volatile unsigned long _junk; \ CALL_FN_W_5W(_junk,fnptr,arg1,arg2,arg3,arg4,arg5); } while (0) #define CALL_FN_v_6W(fnptr, arg1,arg2,arg3,arg4,arg5,arg6) \ do { volatile unsigned long _junk; \ CALL_FN_W_6W(_junk,fnptr,arg1,arg2,arg3,arg4,arg5,arg6); } while (0) #define CALL_FN_v_7W(fnptr, arg1,arg2,arg3,arg4,arg5,arg6,arg7) \ do { volatile unsigned long _junk; \ CALL_FN_W_7W(_junk,fnptr,arg1,arg2,arg3,arg4,arg5,arg6,arg7); } while (0) /* ----------------- x86-{linux,darwin,solaris} ---------------- */ #if defined(PLAT_x86_linux) || defined(PLAT_x86_darwin) \ || defined(PLAT_x86_solaris) /* These regs are trashed by the hidden call. No need to mention eax as gcc can already see that, plus causes gcc to bomb. */ #define __CALLER_SAVED_REGS /*"eax"*/ "ecx", "edx" /* Macros to save and align the stack before making a function call and restore it afterwards as gcc may not keep the stack pointer aligned if it doesn't realise calls are being made to other functions. */ #define VALGRIND_ALIGN_STACK \ "movl %%esp,%%edi\n\t" \ "andl $0xfffffff0,%%esp\n\t" #define VALGRIND_RESTORE_STACK \ "movl %%edi,%%esp\n\t" /* These CALL_FN_ macros assume that on x86-linux, sizeof(unsigned long) == 4. */ #define CALL_FN_W_v(lval, orig) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[1]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "movl (%%eax), %%eax\n\t" /* target->%eax */ \ VALGRIND_CALL_NOREDIR_EAX \ VALGRIND_RESTORE_STACK \ : /*out*/ "=a" (_res) \ : /*in*/ "a" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "edi" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_W(lval, orig, arg1) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[2]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "subl $12, %%esp\n\t" \ "pushl 4(%%eax)\n\t" \ "movl (%%eax), %%eax\n\t" /* target->%eax */ \ VALGRIND_CALL_NOREDIR_EAX \ VALGRIND_RESTORE_STACK \ : /*out*/ "=a" (_res) \ : /*in*/ "a" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "edi" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WW(lval, orig, arg1,arg2) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "subl $8, %%esp\n\t" \ "pushl 8(%%eax)\n\t" \ "pushl 4(%%eax)\n\t" \ "movl (%%eax), %%eax\n\t" /* target->%eax */ \ VALGRIND_CALL_NOREDIR_EAX \ VALGRIND_RESTORE_STACK \ : /*out*/ "=a" (_res) \ : /*in*/ "a" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "edi" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[4]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "subl $4, %%esp\n\t" \ "pushl 12(%%eax)\n\t" \ "pushl 8(%%eax)\n\t" \ "pushl 4(%%eax)\n\t" \ "movl (%%eax), %%eax\n\t" /* target->%eax */ \ VALGRIND_CALL_NOREDIR_EAX \ VALGRIND_RESTORE_STACK \ : /*out*/ "=a" (_res) \ : /*in*/ "a" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "edi" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[5]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "pushl 16(%%eax)\n\t" \ "pushl 12(%%eax)\n\t" \ "pushl 8(%%eax)\n\t" \ "pushl 4(%%eax)\n\t" \ "movl (%%eax), %%eax\n\t" /* target->%eax */ \ VALGRIND_CALL_NOREDIR_EAX \ VALGRIND_RESTORE_STACK \ : /*out*/ "=a" (_res) \ : /*in*/ "a" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "edi" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[6]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "subl $12, %%esp\n\t" \ "pushl 20(%%eax)\n\t" \ "pushl 16(%%eax)\n\t" \ "pushl 12(%%eax)\n\t" \ "pushl 8(%%eax)\n\t" \ "pushl 4(%%eax)\n\t" \ "movl (%%eax), %%eax\n\t" /* target->%eax */ \ VALGRIND_CALL_NOREDIR_EAX \ VALGRIND_RESTORE_STACK \ : /*out*/ "=a" (_res) \ : /*in*/ "a" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "edi" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[7]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "subl $8, %%esp\n\t" \ "pushl 24(%%eax)\n\t" \ "pushl 20(%%eax)\n\t" \ "pushl 16(%%eax)\n\t" \ "pushl 12(%%eax)\n\t" \ "pushl 8(%%eax)\n\t" \ "pushl 4(%%eax)\n\t" \ "movl (%%eax), %%eax\n\t" /* target->%eax */ \ VALGRIND_CALL_NOREDIR_EAX \ VALGRIND_RESTORE_STACK \ : /*out*/ "=a" (_res) \ : /*in*/ "a" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "edi" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[8]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "subl $4, %%esp\n\t" \ "pushl 28(%%eax)\n\t" \ "pushl 24(%%eax)\n\t" \ "pushl 20(%%eax)\n\t" \ "pushl 16(%%eax)\n\t" \ "pushl 12(%%eax)\n\t" \ "pushl 8(%%eax)\n\t" \ "pushl 4(%%eax)\n\t" \ "movl (%%eax), %%eax\n\t" /* target->%eax */ \ VALGRIND_CALL_NOREDIR_EAX \ VALGRIND_RESTORE_STACK \ : /*out*/ "=a" (_res) \ : /*in*/ "a" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "edi" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[9]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "pushl 32(%%eax)\n\t" \ "pushl 28(%%eax)\n\t" \ "pushl 24(%%eax)\n\t" \ "pushl 20(%%eax)\n\t" \ "pushl 16(%%eax)\n\t" \ "pushl 12(%%eax)\n\t" \ "pushl 8(%%eax)\n\t" \ "pushl 4(%%eax)\n\t" \ "movl (%%eax), %%eax\n\t" /* target->%eax */ \ VALGRIND_CALL_NOREDIR_EAX \ VALGRIND_RESTORE_STACK \ : /*out*/ "=a" (_res) \ : /*in*/ "a" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "edi" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[10]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ _argvec[9] = (unsigned long)(arg9); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "subl $12, %%esp\n\t" \ "pushl 36(%%eax)\n\t" \ "pushl 32(%%eax)\n\t" \ "pushl 28(%%eax)\n\t" \ "pushl 24(%%eax)\n\t" \ "pushl 20(%%eax)\n\t" \ "pushl 16(%%eax)\n\t" \ "pushl 12(%%eax)\n\t" \ "pushl 8(%%eax)\n\t" \ "pushl 4(%%eax)\n\t" \ "movl (%%eax), %%eax\n\t" /* target->%eax */ \ VALGRIND_CALL_NOREDIR_EAX \ VALGRIND_RESTORE_STACK \ : /*out*/ "=a" (_res) \ : /*in*/ "a" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "edi" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9,arg10) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[11]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ _argvec[9] = (unsigned long)(arg9); \ _argvec[10] = (unsigned long)(arg10); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "subl $8, %%esp\n\t" \ "pushl 40(%%eax)\n\t" \ "pushl 36(%%eax)\n\t" \ "pushl 32(%%eax)\n\t" \ "pushl 28(%%eax)\n\t" \ "pushl 24(%%eax)\n\t" \ "pushl 20(%%eax)\n\t" \ "pushl 16(%%eax)\n\t" \ "pushl 12(%%eax)\n\t" \ "pushl 8(%%eax)\n\t" \ "pushl 4(%%eax)\n\t" \ "movl (%%eax), %%eax\n\t" /* target->%eax */ \ VALGRIND_CALL_NOREDIR_EAX \ VALGRIND_RESTORE_STACK \ : /*out*/ "=a" (_res) \ : /*in*/ "a" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "edi" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5, \ arg6,arg7,arg8,arg9,arg10, \ arg11) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[12]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ _argvec[9] = (unsigned long)(arg9); \ _argvec[10] = (unsigned long)(arg10); \ _argvec[11] = (unsigned long)(arg11); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "subl $4, %%esp\n\t" \ "pushl 44(%%eax)\n\t" \ "pushl 40(%%eax)\n\t" \ "pushl 36(%%eax)\n\t" \ "pushl 32(%%eax)\n\t" \ "pushl 28(%%eax)\n\t" \ "pushl 24(%%eax)\n\t" \ "pushl 20(%%eax)\n\t" \ "pushl 16(%%eax)\n\t" \ "pushl 12(%%eax)\n\t" \ "pushl 8(%%eax)\n\t" \ "pushl 4(%%eax)\n\t" \ "movl (%%eax), %%eax\n\t" /* target->%eax */ \ VALGRIND_CALL_NOREDIR_EAX \ VALGRIND_RESTORE_STACK \ : /*out*/ "=a" (_res) \ : /*in*/ "a" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "edi" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5, \ arg6,arg7,arg8,arg9,arg10, \ arg11,arg12) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[13]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ _argvec[9] = (unsigned long)(arg9); \ _argvec[10] = (unsigned long)(arg10); \ _argvec[11] = (unsigned long)(arg11); \ _argvec[12] = (unsigned long)(arg12); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "pushl 48(%%eax)\n\t" \ "pushl 44(%%eax)\n\t" \ "pushl 40(%%eax)\n\t" \ "pushl 36(%%eax)\n\t" \ "pushl 32(%%eax)\n\t" \ "pushl 28(%%eax)\n\t" \ "pushl 24(%%eax)\n\t" \ "pushl 20(%%eax)\n\t" \ "pushl 16(%%eax)\n\t" \ "pushl 12(%%eax)\n\t" \ "pushl 8(%%eax)\n\t" \ "pushl 4(%%eax)\n\t" \ "movl (%%eax), %%eax\n\t" /* target->%eax */ \ VALGRIND_CALL_NOREDIR_EAX \ VALGRIND_RESTORE_STACK \ : /*out*/ "=a" (_res) \ : /*in*/ "a" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "edi" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #endif /* PLAT_x86_linux || PLAT_x86_darwin || PLAT_x86_solaris */ /* ---------------- amd64-{linux,darwin,solaris} --------------- */ #if defined(PLAT_amd64_linux) || defined(PLAT_amd64_darwin) \ || defined(PLAT_amd64_solaris) /* ARGREGS: rdi rsi rdx rcx r8 r9 (the rest on stack in R-to-L order) */ /* These regs are trashed by the hidden call. */ #define __CALLER_SAVED_REGS /*"rax",*/ "rcx", "rdx", "rsi", \ "rdi", "r8", "r9", "r10", "r11" /* This is all pretty complex. It's so as to make stack unwinding work reliably. See bug 243270. The basic problem is the sub and add of 128 of %rsp in all of the following macros. If gcc believes the CFA is in %rsp, then unwinding may fail, because what's at the CFA is not what gcc "expected" when it constructs the CFIs for the places where the macros are instantiated. But we can't just add a CFI annotation to increase the CFA offset by 128, to match the sub of 128 from %rsp, because we don't know whether gcc has chosen %rsp as the CFA at that point, or whether it has chosen some other register (eg, %rbp). In the latter case, adding a CFI annotation to change the CFA offset is simply wrong. So the solution is to get hold of the CFA using __builtin_dwarf_cfa(), put it in a known register, and add a CFI annotation to say what the register is. We choose %rbp for this (perhaps perversely), because: (1) %rbp is already subject to unwinding. If a new register was chosen then the unwinder would have to unwind it in all stack traces, which is expensive, and (2) %rbp is already subject to precise exception updates in the JIT. If a new register was chosen, we'd have to have precise exceptions for it too, which reduces performance of the generated code. However .. one extra complication. We can't just whack the result of __builtin_dwarf_cfa() into %rbp and then add %rbp to the list of trashed registers at the end of the inline assembly fragments; gcc won't allow %rbp to appear in that list. Hence instead we need to stash %rbp in %r15 for the duration of the asm, and say that %r15 is trashed instead. gcc seems happy to go with that. Oh .. and this all needs to be conditionalised so that it is unchanged from before this commit, when compiled with older gccs that don't support __builtin_dwarf_cfa. Furthermore, since this header file is freestanding, it has to be independent of config.h, and so the following conditionalisation cannot depend on configure time checks. Although it's not clear from 'defined(__GNUC__) && defined(__GCC_HAVE_DWARF2_CFI_ASM)', this expression excludes Darwin. .cfi directives in Darwin assembly appear to be completely different and I haven't investigated how they work. For even more entertainment value, note we have to use the completely undocumented __builtin_dwarf_cfa(), which appears to really compute the CFA, whereas __builtin_frame_address(0) claims to but actually doesn't. See https://bugs.kde.org/show_bug.cgi?id=243270#c47 */ #if defined(__GNUC__) && defined(__GCC_HAVE_DWARF2_CFI_ASM) # define __FRAME_POINTER \ ,"r"(__builtin_dwarf_cfa()) # define VALGRIND_CFI_PROLOGUE \ "movq %%rbp, %%r15\n\t" \ "movq %2, %%rbp\n\t" \ ".cfi_remember_state\n\t" \ ".cfi_def_cfa rbp, 0\n\t" # define VALGRIND_CFI_EPILOGUE \ "movq %%r15, %%rbp\n\t" \ ".cfi_restore_state\n\t" #else # define __FRAME_POINTER # define VALGRIND_CFI_PROLOGUE # define VALGRIND_CFI_EPILOGUE #endif /* Macros to save and align the stack before making a function call and restore it afterwards as gcc may not keep the stack pointer aligned if it doesn't realise calls are being made to other functions. */ #define VALGRIND_ALIGN_STACK \ "movq %%rsp,%%r14\n\t" \ "andq $0xfffffffffffffff0,%%rsp\n\t" #define VALGRIND_RESTORE_STACK \ "movq %%r14,%%rsp\n\t" /* These CALL_FN_ macros assume that on amd64-linux, sizeof(unsigned long) == 8. */ /* NB 9 Sept 07. There is a nasty kludge here in all these CALL_FN_ macros. In order not to trash the stack redzone, we need to drop %rsp by 128 before the hidden call, and restore afterwards. The nastyness is that it is only by luck that the stack still appears to be unwindable during the hidden call - since then the behaviour of any routine using this macro does not match what the CFI data says. Sigh. Why is this important? Imagine that a wrapper has a stack allocated local, and passes to the hidden call, a pointer to it. Because gcc does not know about the hidden call, it may allocate that local in the redzone. Unfortunately the hidden call may then trash it before it comes to use it. So we must step clear of the redzone, for the duration of the hidden call, to make it safe. Probably the same problem afflicts the other redzone-style ABIs too (ppc64-linux); but for those, the stack is self describing (none of this CFI nonsense) so at least messing with the stack pointer doesn't give a danger of non-unwindable stack. */ #define CALL_FN_W_v(lval, orig) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[1]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ __asm__ volatile( \ VALGRIND_CFI_PROLOGUE \ VALGRIND_ALIGN_STACK \ "subq $128,%%rsp\n\t" \ "movq (%%rax), %%rax\n\t" /* target->%rax */ \ VALGRIND_CALL_NOREDIR_RAX \ VALGRIND_RESTORE_STACK \ VALGRIND_CFI_EPILOGUE \ : /*out*/ "=a" (_res) \ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r14", "r15" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_W(lval, orig, arg1) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[2]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ __asm__ volatile( \ VALGRIND_CFI_PROLOGUE \ VALGRIND_ALIGN_STACK \ "subq $128,%%rsp\n\t" \ "movq 8(%%rax), %%rdi\n\t" \ "movq (%%rax), %%rax\n\t" /* target->%rax */ \ VALGRIND_CALL_NOREDIR_RAX \ VALGRIND_RESTORE_STACK \ VALGRIND_CFI_EPILOGUE \ : /*out*/ "=a" (_res) \ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r14", "r15" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WW(lval, orig, arg1,arg2) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ __asm__ volatile( \ VALGRIND_CFI_PROLOGUE \ VALGRIND_ALIGN_STACK \ "subq $128,%%rsp\n\t" \ "movq 16(%%rax), %%rsi\n\t" \ "movq 8(%%rax), %%rdi\n\t" \ "movq (%%rax), %%rax\n\t" /* target->%rax */ \ VALGRIND_CALL_NOREDIR_RAX \ VALGRIND_RESTORE_STACK \ VALGRIND_CFI_EPILOGUE \ : /*out*/ "=a" (_res) \ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r14", "r15" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[4]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ __asm__ volatile( \ VALGRIND_CFI_PROLOGUE \ VALGRIND_ALIGN_STACK \ "subq $128,%%rsp\n\t" \ "movq 24(%%rax), %%rdx\n\t" \ "movq 16(%%rax), %%rsi\n\t" \ "movq 8(%%rax), %%rdi\n\t" \ "movq (%%rax), %%rax\n\t" /* target->%rax */ \ VALGRIND_CALL_NOREDIR_RAX \ VALGRIND_RESTORE_STACK \ VALGRIND_CFI_EPILOGUE \ : /*out*/ "=a" (_res) \ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r14", "r15" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[5]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ __asm__ volatile( \ VALGRIND_CFI_PROLOGUE \ VALGRIND_ALIGN_STACK \ "subq $128,%%rsp\n\t" \ "movq 32(%%rax), %%rcx\n\t" \ "movq 24(%%rax), %%rdx\n\t" \ "movq 16(%%rax), %%rsi\n\t" \ "movq 8(%%rax), %%rdi\n\t" \ "movq (%%rax), %%rax\n\t" /* target->%rax */ \ VALGRIND_CALL_NOREDIR_RAX \ VALGRIND_RESTORE_STACK \ VALGRIND_CFI_EPILOGUE \ : /*out*/ "=a" (_res) \ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r14", "r15" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[6]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ __asm__ volatile( \ VALGRIND_CFI_PROLOGUE \ VALGRIND_ALIGN_STACK \ "subq $128,%%rsp\n\t" \ "movq 40(%%rax), %%r8\n\t" \ "movq 32(%%rax), %%rcx\n\t" \ "movq 24(%%rax), %%rdx\n\t" \ "movq 16(%%rax), %%rsi\n\t" \ "movq 8(%%rax), %%rdi\n\t" \ "movq (%%rax), %%rax\n\t" /* target->%rax */ \ VALGRIND_CALL_NOREDIR_RAX \ VALGRIND_RESTORE_STACK \ VALGRIND_CFI_EPILOGUE \ : /*out*/ "=a" (_res) \ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r14", "r15" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[7]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ __asm__ volatile( \ VALGRIND_CFI_PROLOGUE \ VALGRIND_ALIGN_STACK \ "subq $128,%%rsp\n\t" \ "movq 48(%%rax), %%r9\n\t" \ "movq 40(%%rax), %%r8\n\t" \ "movq 32(%%rax), %%rcx\n\t" \ "movq 24(%%rax), %%rdx\n\t" \ "movq 16(%%rax), %%rsi\n\t" \ "movq 8(%%rax), %%rdi\n\t" \ "movq (%%rax), %%rax\n\t" /* target->%rax */ \ VALGRIND_CALL_NOREDIR_RAX \ VALGRIND_RESTORE_STACK \ VALGRIND_CFI_EPILOGUE \ : /*out*/ "=a" (_res) \ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r14", "r15" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[8]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ __asm__ volatile( \ VALGRIND_CFI_PROLOGUE \ VALGRIND_ALIGN_STACK \ "subq $136,%%rsp\n\t" \ "pushq 56(%%rax)\n\t" \ "movq 48(%%rax), %%r9\n\t" \ "movq 40(%%rax), %%r8\n\t" \ "movq 32(%%rax), %%rcx\n\t" \ "movq 24(%%rax), %%rdx\n\t" \ "movq 16(%%rax), %%rsi\n\t" \ "movq 8(%%rax), %%rdi\n\t" \ "movq (%%rax), %%rax\n\t" /* target->%rax */ \ VALGRIND_CALL_NOREDIR_RAX \ VALGRIND_RESTORE_STACK \ VALGRIND_CFI_EPILOGUE \ : /*out*/ "=a" (_res) \ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r14", "r15" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[9]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ __asm__ volatile( \ VALGRIND_CFI_PROLOGUE \ VALGRIND_ALIGN_STACK \ "subq $128,%%rsp\n\t" \ "pushq 64(%%rax)\n\t" \ "pushq 56(%%rax)\n\t" \ "movq 48(%%rax), %%r9\n\t" \ "movq 40(%%rax), %%r8\n\t" \ "movq 32(%%rax), %%rcx\n\t" \ "movq 24(%%rax), %%rdx\n\t" \ "movq 16(%%rax), %%rsi\n\t" \ "movq 8(%%rax), %%rdi\n\t" \ "movq (%%rax), %%rax\n\t" /* target->%rax */ \ VALGRIND_CALL_NOREDIR_RAX \ VALGRIND_RESTORE_STACK \ VALGRIND_CFI_EPILOGUE \ : /*out*/ "=a" (_res) \ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r14", "r15" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[10]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ _argvec[9] = (unsigned long)(arg9); \ __asm__ volatile( \ VALGRIND_CFI_PROLOGUE \ VALGRIND_ALIGN_STACK \ "subq $136,%%rsp\n\t" \ "pushq 72(%%rax)\n\t" \ "pushq 64(%%rax)\n\t" \ "pushq 56(%%rax)\n\t" \ "movq 48(%%rax), %%r9\n\t" \ "movq 40(%%rax), %%r8\n\t" \ "movq 32(%%rax), %%rcx\n\t" \ "movq 24(%%rax), %%rdx\n\t" \ "movq 16(%%rax), %%rsi\n\t" \ "movq 8(%%rax), %%rdi\n\t" \ "movq (%%rax), %%rax\n\t" /* target->%rax */ \ VALGRIND_CALL_NOREDIR_RAX \ VALGRIND_RESTORE_STACK \ VALGRIND_CFI_EPILOGUE \ : /*out*/ "=a" (_res) \ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r14", "r15" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9,arg10) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[11]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ _argvec[9] = (unsigned long)(arg9); \ _argvec[10] = (unsigned long)(arg10); \ __asm__ volatile( \ VALGRIND_CFI_PROLOGUE \ VALGRIND_ALIGN_STACK \ "subq $128,%%rsp\n\t" \ "pushq 80(%%rax)\n\t" \ "pushq 72(%%rax)\n\t" \ "pushq 64(%%rax)\n\t" \ "pushq 56(%%rax)\n\t" \ "movq 48(%%rax), %%r9\n\t" \ "movq 40(%%rax), %%r8\n\t" \ "movq 32(%%rax), %%rcx\n\t" \ "movq 24(%%rax), %%rdx\n\t" \ "movq 16(%%rax), %%rsi\n\t" \ "movq 8(%%rax), %%rdi\n\t" \ "movq (%%rax), %%rax\n\t" /* target->%rax */ \ VALGRIND_CALL_NOREDIR_RAX \ VALGRIND_RESTORE_STACK \ VALGRIND_CFI_EPILOGUE \ : /*out*/ "=a" (_res) \ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r14", "r15" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9,arg10,arg11) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[12]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ _argvec[9] = (unsigned long)(arg9); \ _argvec[10] = (unsigned long)(arg10); \ _argvec[11] = (unsigned long)(arg11); \ __asm__ volatile( \ VALGRIND_CFI_PROLOGUE \ VALGRIND_ALIGN_STACK \ "subq $136,%%rsp\n\t" \ "pushq 88(%%rax)\n\t" \ "pushq 80(%%rax)\n\t" \ "pushq 72(%%rax)\n\t" \ "pushq 64(%%rax)\n\t" \ "pushq 56(%%rax)\n\t" \ "movq 48(%%rax), %%r9\n\t" \ "movq 40(%%rax), %%r8\n\t" \ "movq 32(%%rax), %%rcx\n\t" \ "movq 24(%%rax), %%rdx\n\t" \ "movq 16(%%rax), %%rsi\n\t" \ "movq 8(%%rax), %%rdi\n\t" \ "movq (%%rax), %%rax\n\t" /* target->%rax */ \ VALGRIND_CALL_NOREDIR_RAX \ VALGRIND_RESTORE_STACK \ VALGRIND_CFI_EPILOGUE \ : /*out*/ "=a" (_res) \ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r14", "r15" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9,arg10,arg11,arg12) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[13]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ _argvec[9] = (unsigned long)(arg9); \ _argvec[10] = (unsigned long)(arg10); \ _argvec[11] = (unsigned long)(arg11); \ _argvec[12] = (unsigned long)(arg12); \ __asm__ volatile( \ VALGRIND_CFI_PROLOGUE \ VALGRIND_ALIGN_STACK \ "subq $128,%%rsp\n\t" \ "pushq 96(%%rax)\n\t" \ "pushq 88(%%rax)\n\t" \ "pushq 80(%%rax)\n\t" \ "pushq 72(%%rax)\n\t" \ "pushq 64(%%rax)\n\t" \ "pushq 56(%%rax)\n\t" \ "movq 48(%%rax), %%r9\n\t" \ "movq 40(%%rax), %%r8\n\t" \ "movq 32(%%rax), %%rcx\n\t" \ "movq 24(%%rax), %%rdx\n\t" \ "movq 16(%%rax), %%rsi\n\t" \ "movq 8(%%rax), %%rdi\n\t" \ "movq (%%rax), %%rax\n\t" /* target->%rax */ \ VALGRIND_CALL_NOREDIR_RAX \ VALGRIND_RESTORE_STACK \ VALGRIND_CFI_EPILOGUE \ : /*out*/ "=a" (_res) \ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r14", "r15" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #endif /* PLAT_amd64_linux || PLAT_amd64_darwin || PLAT_amd64_solaris */ /* ------------------------ ppc32-linux ------------------------ */ #if defined(PLAT_ppc32_linux) /* This is useful for finding out about the on-stack stuff: extern int f9 ( int,int,int,int,int,int,int,int,int ); extern int f10 ( int,int,int,int,int,int,int,int,int,int ); extern int f11 ( int,int,int,int,int,int,int,int,int,int,int ); extern int f12 ( int,int,int,int,int,int,int,int,int,int,int,int ); int g9 ( void ) { return f9(11,22,33,44,55,66,77,88,99); } int g10 ( void ) { return f10(11,22,33,44,55,66,77,88,99,110); } int g11 ( void ) { return f11(11,22,33,44,55,66,77,88,99,110,121); } int g12 ( void ) { return f12(11,22,33,44,55,66,77,88,99,110,121,132); } */ /* ARGREGS: r3 r4 r5 r6 r7 r8 r9 r10 (the rest on stack somewhere) */ /* These regs are trashed by the hidden call. */ #define __CALLER_SAVED_REGS \ "lr", "ctr", "xer", \ "cr0", "cr1", "cr2", "cr3", "cr4", "cr5", "cr6", "cr7", \ "r0", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", \ "r11", "r12", "r13" /* Macros to save and align the stack before making a function call and restore it afterwards as gcc may not keep the stack pointer aligned if it doesn't realise calls are being made to other functions. */ #define VALGRIND_ALIGN_STACK \ "mr 28,1\n\t" \ "rlwinm 1,1,0,0,27\n\t" #define VALGRIND_RESTORE_STACK \ "mr 1,28\n\t" /* These CALL_FN_ macros assume that on ppc32-linux, sizeof(unsigned long) == 4. */ #define CALL_FN_W_v(lval, orig) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[1]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 11,%1\n\t" \ "lwz 11,0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ VALGRIND_RESTORE_STACK \ "mr %0,3" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_W(lval, orig, arg1) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[2]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)arg1; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 11,%1\n\t" \ "lwz 3,4(11)\n\t" /* arg1->r3 */ \ "lwz 11,0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ VALGRIND_RESTORE_STACK \ "mr %0,3" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WW(lval, orig, arg1,arg2) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)arg1; \ _argvec[2] = (unsigned long)arg2; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 11,%1\n\t" \ "lwz 3,4(11)\n\t" /* arg1->r3 */ \ "lwz 4,8(11)\n\t" \ "lwz 11,0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ VALGRIND_RESTORE_STACK \ "mr %0,3" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[4]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)arg1; \ _argvec[2] = (unsigned long)arg2; \ _argvec[3] = (unsigned long)arg3; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 11,%1\n\t" \ "lwz 3,4(11)\n\t" /* arg1->r3 */ \ "lwz 4,8(11)\n\t" \ "lwz 5,12(11)\n\t" \ "lwz 11,0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ VALGRIND_RESTORE_STACK \ "mr %0,3" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[5]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)arg1; \ _argvec[2] = (unsigned long)arg2; \ _argvec[3] = (unsigned long)arg3; \ _argvec[4] = (unsigned long)arg4; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 11,%1\n\t" \ "lwz 3,4(11)\n\t" /* arg1->r3 */ \ "lwz 4,8(11)\n\t" \ "lwz 5,12(11)\n\t" \ "lwz 6,16(11)\n\t" /* arg4->r6 */ \ "lwz 11,0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ VALGRIND_RESTORE_STACK \ "mr %0,3" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[6]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)arg1; \ _argvec[2] = (unsigned long)arg2; \ _argvec[3] = (unsigned long)arg3; \ _argvec[4] = (unsigned long)arg4; \ _argvec[5] = (unsigned long)arg5; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 11,%1\n\t" \ "lwz 3,4(11)\n\t" /* arg1->r3 */ \ "lwz 4,8(11)\n\t" \ "lwz 5,12(11)\n\t" \ "lwz 6,16(11)\n\t" /* arg4->r6 */ \ "lwz 7,20(11)\n\t" \ "lwz 11,0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ VALGRIND_RESTORE_STACK \ "mr %0,3" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[7]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)arg1; \ _argvec[2] = (unsigned long)arg2; \ _argvec[3] = (unsigned long)arg3; \ _argvec[4] = (unsigned long)arg4; \ _argvec[5] = (unsigned long)arg5; \ _argvec[6] = (unsigned long)arg6; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 11,%1\n\t" \ "lwz 3,4(11)\n\t" /* arg1->r3 */ \ "lwz 4,8(11)\n\t" \ "lwz 5,12(11)\n\t" \ "lwz 6,16(11)\n\t" /* arg4->r6 */ \ "lwz 7,20(11)\n\t" \ "lwz 8,24(11)\n\t" \ "lwz 11,0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ VALGRIND_RESTORE_STACK \ "mr %0,3" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[8]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)arg1; \ _argvec[2] = (unsigned long)arg2; \ _argvec[3] = (unsigned long)arg3; \ _argvec[4] = (unsigned long)arg4; \ _argvec[5] = (unsigned long)arg5; \ _argvec[6] = (unsigned long)arg6; \ _argvec[7] = (unsigned long)arg7; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 11,%1\n\t" \ "lwz 3,4(11)\n\t" /* arg1->r3 */ \ "lwz 4,8(11)\n\t" \ "lwz 5,12(11)\n\t" \ "lwz 6,16(11)\n\t" /* arg4->r6 */ \ "lwz 7,20(11)\n\t" \ "lwz 8,24(11)\n\t" \ "lwz 9,28(11)\n\t" \ "lwz 11,0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ VALGRIND_RESTORE_STACK \ "mr %0,3" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[9]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)arg1; \ _argvec[2] = (unsigned long)arg2; \ _argvec[3] = (unsigned long)arg3; \ _argvec[4] = (unsigned long)arg4; \ _argvec[5] = (unsigned long)arg5; \ _argvec[6] = (unsigned long)arg6; \ _argvec[7] = (unsigned long)arg7; \ _argvec[8] = (unsigned long)arg8; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 11,%1\n\t" \ "lwz 3,4(11)\n\t" /* arg1->r3 */ \ "lwz 4,8(11)\n\t" \ "lwz 5,12(11)\n\t" \ "lwz 6,16(11)\n\t" /* arg4->r6 */ \ "lwz 7,20(11)\n\t" \ "lwz 8,24(11)\n\t" \ "lwz 9,28(11)\n\t" \ "lwz 10,32(11)\n\t" /* arg8->r10 */ \ "lwz 11,0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ VALGRIND_RESTORE_STACK \ "mr %0,3" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[10]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)arg1; \ _argvec[2] = (unsigned long)arg2; \ _argvec[3] = (unsigned long)arg3; \ _argvec[4] = (unsigned long)arg4; \ _argvec[5] = (unsigned long)arg5; \ _argvec[6] = (unsigned long)arg6; \ _argvec[7] = (unsigned long)arg7; \ _argvec[8] = (unsigned long)arg8; \ _argvec[9] = (unsigned long)arg9; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 11,%1\n\t" \ "addi 1,1,-16\n\t" \ /* arg9 */ \ "lwz 3,36(11)\n\t" \ "stw 3,8(1)\n\t" \ /* args1-8 */ \ "lwz 3,4(11)\n\t" /* arg1->r3 */ \ "lwz 4,8(11)\n\t" \ "lwz 5,12(11)\n\t" \ "lwz 6,16(11)\n\t" /* arg4->r6 */ \ "lwz 7,20(11)\n\t" \ "lwz 8,24(11)\n\t" \ "lwz 9,28(11)\n\t" \ "lwz 10,32(11)\n\t" /* arg8->r10 */ \ "lwz 11,0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ VALGRIND_RESTORE_STACK \ "mr %0,3" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9,arg10) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[11]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)arg1; \ _argvec[2] = (unsigned long)arg2; \ _argvec[3] = (unsigned long)arg3; \ _argvec[4] = (unsigned long)arg4; \ _argvec[5] = (unsigned long)arg5; \ _argvec[6] = (unsigned long)arg6; \ _argvec[7] = (unsigned long)arg7; \ _argvec[8] = (unsigned long)arg8; \ _argvec[9] = (unsigned long)arg9; \ _argvec[10] = (unsigned long)arg10; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 11,%1\n\t" \ "addi 1,1,-16\n\t" \ /* arg10 */ \ "lwz 3,40(11)\n\t" \ "stw 3,12(1)\n\t" \ /* arg9 */ \ "lwz 3,36(11)\n\t" \ "stw 3,8(1)\n\t" \ /* args1-8 */ \ "lwz 3,4(11)\n\t" /* arg1->r3 */ \ "lwz 4,8(11)\n\t" \ "lwz 5,12(11)\n\t" \ "lwz 6,16(11)\n\t" /* arg4->r6 */ \ "lwz 7,20(11)\n\t" \ "lwz 8,24(11)\n\t" \ "lwz 9,28(11)\n\t" \ "lwz 10,32(11)\n\t" /* arg8->r10 */ \ "lwz 11,0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ VALGRIND_RESTORE_STACK \ "mr %0,3" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9,arg10,arg11) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[12]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)arg1; \ _argvec[2] = (unsigned long)arg2; \ _argvec[3] = (unsigned long)arg3; \ _argvec[4] = (unsigned long)arg4; \ _argvec[5] = (unsigned long)arg5; \ _argvec[6] = (unsigned long)arg6; \ _argvec[7] = (unsigned long)arg7; \ _argvec[8] = (unsigned long)arg8; \ _argvec[9] = (unsigned long)arg9; \ _argvec[10] = (unsigned long)arg10; \ _argvec[11] = (unsigned long)arg11; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 11,%1\n\t" \ "addi 1,1,-32\n\t" \ /* arg11 */ \ "lwz 3,44(11)\n\t" \ "stw 3,16(1)\n\t" \ /* arg10 */ \ "lwz 3,40(11)\n\t" \ "stw 3,12(1)\n\t" \ /* arg9 */ \ "lwz 3,36(11)\n\t" \ "stw 3,8(1)\n\t" \ /* args1-8 */ \ "lwz 3,4(11)\n\t" /* arg1->r3 */ \ "lwz 4,8(11)\n\t" \ "lwz 5,12(11)\n\t" \ "lwz 6,16(11)\n\t" /* arg4->r6 */ \ "lwz 7,20(11)\n\t" \ "lwz 8,24(11)\n\t" \ "lwz 9,28(11)\n\t" \ "lwz 10,32(11)\n\t" /* arg8->r10 */ \ "lwz 11,0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ VALGRIND_RESTORE_STACK \ "mr %0,3" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9,arg10,arg11,arg12) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[13]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)arg1; \ _argvec[2] = (unsigned long)arg2; \ _argvec[3] = (unsigned long)arg3; \ _argvec[4] = (unsigned long)arg4; \ _argvec[5] = (unsigned long)arg5; \ _argvec[6] = (unsigned long)arg6; \ _argvec[7] = (unsigned long)arg7; \ _argvec[8] = (unsigned long)arg8; \ _argvec[9] = (unsigned long)arg9; \ _argvec[10] = (unsigned long)arg10; \ _argvec[11] = (unsigned long)arg11; \ _argvec[12] = (unsigned long)arg12; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 11,%1\n\t" \ "addi 1,1,-32\n\t" \ /* arg12 */ \ "lwz 3,48(11)\n\t" \ "stw 3,20(1)\n\t" \ /* arg11 */ \ "lwz 3,44(11)\n\t" \ "stw 3,16(1)\n\t" \ /* arg10 */ \ "lwz 3,40(11)\n\t" \ "stw 3,12(1)\n\t" \ /* arg9 */ \ "lwz 3,36(11)\n\t" \ "stw 3,8(1)\n\t" \ /* args1-8 */ \ "lwz 3,4(11)\n\t" /* arg1->r3 */ \ "lwz 4,8(11)\n\t" \ "lwz 5,12(11)\n\t" \ "lwz 6,16(11)\n\t" /* arg4->r6 */ \ "lwz 7,20(11)\n\t" \ "lwz 8,24(11)\n\t" \ "lwz 9,28(11)\n\t" \ "lwz 10,32(11)\n\t" /* arg8->r10 */ \ "lwz 11,0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ VALGRIND_RESTORE_STACK \ "mr %0,3" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #endif /* PLAT_ppc32_linux */ /* ------------------------ ppc64-linux ------------------------ */ #if defined(PLAT_ppc64be_linux) /* ARGREGS: r3 r4 r5 r6 r7 r8 r9 r10 (the rest on stack somewhere) */ /* These regs are trashed by the hidden call. */ #define __CALLER_SAVED_REGS \ "lr", "ctr", "xer", \ "cr0", "cr1", "cr2", "cr3", "cr4", "cr5", "cr6", "cr7", \ "r0", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", \ "r11", "r12", "r13" /* Macros to save and align the stack before making a function call and restore it afterwards as gcc may not keep the stack pointer aligned if it doesn't realise calls are being made to other functions. */ #define VALGRIND_ALIGN_STACK \ "mr 28,1\n\t" \ "rldicr 1,1,0,59\n\t" #define VALGRIND_RESTORE_STACK \ "mr 1,28\n\t" /* These CALL_FN_ macros assume that on ppc64-linux, sizeof(unsigned long) == 8. */ #define CALL_FN_W_v(lval, orig) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+0]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 11,%1\n\t" \ "std 2,-16(11)\n\t" /* save tocptr */ \ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ "ld 11, 0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ "mr 11,%1\n\t" \ "mr %0,3\n\t" \ "ld 2,-16(11)\n\t" /* restore tocptr */ \ VALGRIND_RESTORE_STACK \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_W(lval, orig, arg1) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+1]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2+1] = (unsigned long)arg1; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 11,%1\n\t" \ "std 2,-16(11)\n\t" /* save tocptr */ \ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ "ld 3, 8(11)\n\t" /* arg1->r3 */ \ "ld 11, 0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ "mr 11,%1\n\t" \ "mr %0,3\n\t" \ "ld 2,-16(11)\n\t" /* restore tocptr */ \ VALGRIND_RESTORE_STACK \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WW(lval, orig, arg1,arg2) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+2]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2+1] = (unsigned long)arg1; \ _argvec[2+2] = (unsigned long)arg2; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 11,%1\n\t" \ "std 2,-16(11)\n\t" /* save tocptr */ \ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ "ld 3, 8(11)\n\t" /* arg1->r3 */ \ "ld 4, 16(11)\n\t" /* arg2->r4 */ \ "ld 11, 0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ "mr 11,%1\n\t" \ "mr %0,3\n\t" \ "ld 2,-16(11)\n\t" /* restore tocptr */ \ VALGRIND_RESTORE_STACK \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+3]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2+1] = (unsigned long)arg1; \ _argvec[2+2] = (unsigned long)arg2; \ _argvec[2+3] = (unsigned long)arg3; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 11,%1\n\t" \ "std 2,-16(11)\n\t" /* save tocptr */ \ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ "ld 3, 8(11)\n\t" /* arg1->r3 */ \ "ld 4, 16(11)\n\t" /* arg2->r4 */ \ "ld 5, 24(11)\n\t" /* arg3->r5 */ \ "ld 11, 0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ "mr 11,%1\n\t" \ "mr %0,3\n\t" \ "ld 2,-16(11)\n\t" /* restore tocptr */ \ VALGRIND_RESTORE_STACK \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+4]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2+1] = (unsigned long)arg1; \ _argvec[2+2] = (unsigned long)arg2; \ _argvec[2+3] = (unsigned long)arg3; \ _argvec[2+4] = (unsigned long)arg4; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 11,%1\n\t" \ "std 2,-16(11)\n\t" /* save tocptr */ \ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ "ld 3, 8(11)\n\t" /* arg1->r3 */ \ "ld 4, 16(11)\n\t" /* arg2->r4 */ \ "ld 5, 24(11)\n\t" /* arg3->r5 */ \ "ld 6, 32(11)\n\t" /* arg4->r6 */ \ "ld 11, 0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ "mr 11,%1\n\t" \ "mr %0,3\n\t" \ "ld 2,-16(11)\n\t" /* restore tocptr */ \ VALGRIND_RESTORE_STACK \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+5]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2+1] = (unsigned long)arg1; \ _argvec[2+2] = (unsigned long)arg2; \ _argvec[2+3] = (unsigned long)arg3; \ _argvec[2+4] = (unsigned long)arg4; \ _argvec[2+5] = (unsigned long)arg5; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 11,%1\n\t" \ "std 2,-16(11)\n\t" /* save tocptr */ \ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ "ld 3, 8(11)\n\t" /* arg1->r3 */ \ "ld 4, 16(11)\n\t" /* arg2->r4 */ \ "ld 5, 24(11)\n\t" /* arg3->r5 */ \ "ld 6, 32(11)\n\t" /* arg4->r6 */ \ "ld 7, 40(11)\n\t" /* arg5->r7 */ \ "ld 11, 0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ "mr 11,%1\n\t" \ "mr %0,3\n\t" \ "ld 2,-16(11)\n\t" /* restore tocptr */ \ VALGRIND_RESTORE_STACK \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+6]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2+1] = (unsigned long)arg1; \ _argvec[2+2] = (unsigned long)arg2; \ _argvec[2+3] = (unsigned long)arg3; \ _argvec[2+4] = (unsigned long)arg4; \ _argvec[2+5] = (unsigned long)arg5; \ _argvec[2+6] = (unsigned long)arg6; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 11,%1\n\t" \ "std 2,-16(11)\n\t" /* save tocptr */ \ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ "ld 3, 8(11)\n\t" /* arg1->r3 */ \ "ld 4, 16(11)\n\t" /* arg2->r4 */ \ "ld 5, 24(11)\n\t" /* arg3->r5 */ \ "ld 6, 32(11)\n\t" /* arg4->r6 */ \ "ld 7, 40(11)\n\t" /* arg5->r7 */ \ "ld 8, 48(11)\n\t" /* arg6->r8 */ \ "ld 11, 0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ "mr 11,%1\n\t" \ "mr %0,3\n\t" \ "ld 2,-16(11)\n\t" /* restore tocptr */ \ VALGRIND_RESTORE_STACK \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+7]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2+1] = (unsigned long)arg1; \ _argvec[2+2] = (unsigned long)arg2; \ _argvec[2+3] = (unsigned long)arg3; \ _argvec[2+4] = (unsigned long)arg4; \ _argvec[2+5] = (unsigned long)arg5; \ _argvec[2+6] = (unsigned long)arg6; \ _argvec[2+7] = (unsigned long)arg7; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 11,%1\n\t" \ "std 2,-16(11)\n\t" /* save tocptr */ \ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ "ld 3, 8(11)\n\t" /* arg1->r3 */ \ "ld 4, 16(11)\n\t" /* arg2->r4 */ \ "ld 5, 24(11)\n\t" /* arg3->r5 */ \ "ld 6, 32(11)\n\t" /* arg4->r6 */ \ "ld 7, 40(11)\n\t" /* arg5->r7 */ \ "ld 8, 48(11)\n\t" /* arg6->r8 */ \ "ld 9, 56(11)\n\t" /* arg7->r9 */ \ "ld 11, 0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ "mr 11,%1\n\t" \ "mr %0,3\n\t" \ "ld 2,-16(11)\n\t" /* restore tocptr */ \ VALGRIND_RESTORE_STACK \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+8]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2+1] = (unsigned long)arg1; \ _argvec[2+2] = (unsigned long)arg2; \ _argvec[2+3] = (unsigned long)arg3; \ _argvec[2+4] = (unsigned long)arg4; \ _argvec[2+5] = (unsigned long)arg5; \ _argvec[2+6] = (unsigned long)arg6; \ _argvec[2+7] = (unsigned long)arg7; \ _argvec[2+8] = (unsigned long)arg8; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 11,%1\n\t" \ "std 2,-16(11)\n\t" /* save tocptr */ \ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ "ld 3, 8(11)\n\t" /* arg1->r3 */ \ "ld 4, 16(11)\n\t" /* arg2->r4 */ \ "ld 5, 24(11)\n\t" /* arg3->r5 */ \ "ld 6, 32(11)\n\t" /* arg4->r6 */ \ "ld 7, 40(11)\n\t" /* arg5->r7 */ \ "ld 8, 48(11)\n\t" /* arg6->r8 */ \ "ld 9, 56(11)\n\t" /* arg7->r9 */ \ "ld 10, 64(11)\n\t" /* arg8->r10 */ \ "ld 11, 0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ "mr 11,%1\n\t" \ "mr %0,3\n\t" \ "ld 2,-16(11)\n\t" /* restore tocptr */ \ VALGRIND_RESTORE_STACK \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+9]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2+1] = (unsigned long)arg1; \ _argvec[2+2] = (unsigned long)arg2; \ _argvec[2+3] = (unsigned long)arg3; \ _argvec[2+4] = (unsigned long)arg4; \ _argvec[2+5] = (unsigned long)arg5; \ _argvec[2+6] = (unsigned long)arg6; \ _argvec[2+7] = (unsigned long)arg7; \ _argvec[2+8] = (unsigned long)arg8; \ _argvec[2+9] = (unsigned long)arg9; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 11,%1\n\t" \ "std 2,-16(11)\n\t" /* save tocptr */ \ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ "addi 1,1,-128\n\t" /* expand stack frame */ \ /* arg9 */ \ "ld 3,72(11)\n\t" \ "std 3,112(1)\n\t" \ /* args1-8 */ \ "ld 3, 8(11)\n\t" /* arg1->r3 */ \ "ld 4, 16(11)\n\t" /* arg2->r4 */ \ "ld 5, 24(11)\n\t" /* arg3->r5 */ \ "ld 6, 32(11)\n\t" /* arg4->r6 */ \ "ld 7, 40(11)\n\t" /* arg5->r7 */ \ "ld 8, 48(11)\n\t" /* arg6->r8 */ \ "ld 9, 56(11)\n\t" /* arg7->r9 */ \ "ld 10, 64(11)\n\t" /* arg8->r10 */ \ "ld 11, 0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ "mr 11,%1\n\t" \ "mr %0,3\n\t" \ "ld 2,-16(11)\n\t" /* restore tocptr */ \ VALGRIND_RESTORE_STACK \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9,arg10) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+10]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2+1] = (unsigned long)arg1; \ _argvec[2+2] = (unsigned long)arg2; \ _argvec[2+3] = (unsigned long)arg3; \ _argvec[2+4] = (unsigned long)arg4; \ _argvec[2+5] = (unsigned long)arg5; \ _argvec[2+6] = (unsigned long)arg6; \ _argvec[2+7] = (unsigned long)arg7; \ _argvec[2+8] = (unsigned long)arg8; \ _argvec[2+9] = (unsigned long)arg9; \ _argvec[2+10] = (unsigned long)arg10; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 11,%1\n\t" \ "std 2,-16(11)\n\t" /* save tocptr */ \ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ "addi 1,1,-128\n\t" /* expand stack frame */ \ /* arg10 */ \ "ld 3,80(11)\n\t" \ "std 3,120(1)\n\t" \ /* arg9 */ \ "ld 3,72(11)\n\t" \ "std 3,112(1)\n\t" \ /* args1-8 */ \ "ld 3, 8(11)\n\t" /* arg1->r3 */ \ "ld 4, 16(11)\n\t" /* arg2->r4 */ \ "ld 5, 24(11)\n\t" /* arg3->r5 */ \ "ld 6, 32(11)\n\t" /* arg4->r6 */ \ "ld 7, 40(11)\n\t" /* arg5->r7 */ \ "ld 8, 48(11)\n\t" /* arg6->r8 */ \ "ld 9, 56(11)\n\t" /* arg7->r9 */ \ "ld 10, 64(11)\n\t" /* arg8->r10 */ \ "ld 11, 0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ "mr 11,%1\n\t" \ "mr %0,3\n\t" \ "ld 2,-16(11)\n\t" /* restore tocptr */ \ VALGRIND_RESTORE_STACK \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9,arg10,arg11) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+11]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2+1] = (unsigned long)arg1; \ _argvec[2+2] = (unsigned long)arg2; \ _argvec[2+3] = (unsigned long)arg3; \ _argvec[2+4] = (unsigned long)arg4; \ _argvec[2+5] = (unsigned long)arg5; \ _argvec[2+6] = (unsigned long)arg6; \ _argvec[2+7] = (unsigned long)arg7; \ _argvec[2+8] = (unsigned long)arg8; \ _argvec[2+9] = (unsigned long)arg9; \ _argvec[2+10] = (unsigned long)arg10; \ _argvec[2+11] = (unsigned long)arg11; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 11,%1\n\t" \ "std 2,-16(11)\n\t" /* save tocptr */ \ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ "addi 1,1,-144\n\t" /* expand stack frame */ \ /* arg11 */ \ "ld 3,88(11)\n\t" \ "std 3,128(1)\n\t" \ /* arg10 */ \ "ld 3,80(11)\n\t" \ "std 3,120(1)\n\t" \ /* arg9 */ \ "ld 3,72(11)\n\t" \ "std 3,112(1)\n\t" \ /* args1-8 */ \ "ld 3, 8(11)\n\t" /* arg1->r3 */ \ "ld 4, 16(11)\n\t" /* arg2->r4 */ \ "ld 5, 24(11)\n\t" /* arg3->r5 */ \ "ld 6, 32(11)\n\t" /* arg4->r6 */ \ "ld 7, 40(11)\n\t" /* arg5->r7 */ \ "ld 8, 48(11)\n\t" /* arg6->r8 */ \ "ld 9, 56(11)\n\t" /* arg7->r9 */ \ "ld 10, 64(11)\n\t" /* arg8->r10 */ \ "ld 11, 0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ "mr 11,%1\n\t" \ "mr %0,3\n\t" \ "ld 2,-16(11)\n\t" /* restore tocptr */ \ VALGRIND_RESTORE_STACK \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9,arg10,arg11,arg12) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+12]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2+1] = (unsigned long)arg1; \ _argvec[2+2] = (unsigned long)arg2; \ _argvec[2+3] = (unsigned long)arg3; \ _argvec[2+4] = (unsigned long)arg4; \ _argvec[2+5] = (unsigned long)arg5; \ _argvec[2+6] = (unsigned long)arg6; \ _argvec[2+7] = (unsigned long)arg7; \ _argvec[2+8] = (unsigned long)arg8; \ _argvec[2+9] = (unsigned long)arg9; \ _argvec[2+10] = (unsigned long)arg10; \ _argvec[2+11] = (unsigned long)arg11; \ _argvec[2+12] = (unsigned long)arg12; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 11,%1\n\t" \ "std 2,-16(11)\n\t" /* save tocptr */ \ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ "addi 1,1,-144\n\t" /* expand stack frame */ \ /* arg12 */ \ "ld 3,96(11)\n\t" \ "std 3,136(1)\n\t" \ /* arg11 */ \ "ld 3,88(11)\n\t" \ "std 3,128(1)\n\t" \ /* arg10 */ \ "ld 3,80(11)\n\t" \ "std 3,120(1)\n\t" \ /* arg9 */ \ "ld 3,72(11)\n\t" \ "std 3,112(1)\n\t" \ /* args1-8 */ \ "ld 3, 8(11)\n\t" /* arg1->r3 */ \ "ld 4, 16(11)\n\t" /* arg2->r4 */ \ "ld 5, 24(11)\n\t" /* arg3->r5 */ \ "ld 6, 32(11)\n\t" /* arg4->r6 */ \ "ld 7, 40(11)\n\t" /* arg5->r7 */ \ "ld 8, 48(11)\n\t" /* arg6->r8 */ \ "ld 9, 56(11)\n\t" /* arg7->r9 */ \ "ld 10, 64(11)\n\t" /* arg8->r10 */ \ "ld 11, 0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ "mr 11,%1\n\t" \ "mr %0,3\n\t" \ "ld 2,-16(11)\n\t" /* restore tocptr */ \ VALGRIND_RESTORE_STACK \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #endif /* PLAT_ppc64be_linux */ /* ------------------------- ppc64le-linux ----------------------- */ #if defined(PLAT_ppc64le_linux) /* ARGREGS: r3 r4 r5 r6 r7 r8 r9 r10 (the rest on stack somewhere) */ /* These regs are trashed by the hidden call. */ #define __CALLER_SAVED_REGS \ "lr", "ctr", "xer", \ "cr0", "cr1", "cr2", "cr3", "cr4", "cr5", "cr6", "cr7", \ "r0", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", \ "r11", "r12", "r13" /* Macros to save and align the stack before making a function call and restore it afterwards as gcc may not keep the stack pointer aligned if it doesn't realise calls are being made to other functions. */ #define VALGRIND_ALIGN_STACK \ "mr 28,1\n\t" \ "rldicr 1,1,0,59\n\t" #define VALGRIND_RESTORE_STACK \ "mr 1,28\n\t" /* These CALL_FN_ macros assume that on ppc64-linux, sizeof(unsigned long) == 8. */ #define CALL_FN_W_v(lval, orig) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+0]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 12,%1\n\t" \ "std 2,-16(12)\n\t" /* save tocptr */ \ "ld 2,-8(12)\n\t" /* use nraddr's tocptr */ \ "ld 12, 0(12)\n\t" /* target->r12 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R12 \ "mr 12,%1\n\t" \ "mr %0,3\n\t" \ "ld 2,-16(12)\n\t" /* restore tocptr */ \ VALGRIND_RESTORE_STACK \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_W(lval, orig, arg1) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+1]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2+1] = (unsigned long)arg1; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 12,%1\n\t" \ "std 2,-16(12)\n\t" /* save tocptr */ \ "ld 2,-8(12)\n\t" /* use nraddr's tocptr */ \ "ld 3, 8(12)\n\t" /* arg1->r3 */ \ "ld 12, 0(12)\n\t" /* target->r12 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R12 \ "mr 12,%1\n\t" \ "mr %0,3\n\t" \ "ld 2,-16(12)\n\t" /* restore tocptr */ \ VALGRIND_RESTORE_STACK \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WW(lval, orig, arg1,arg2) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+2]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2+1] = (unsigned long)arg1; \ _argvec[2+2] = (unsigned long)arg2; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 12,%1\n\t" \ "std 2,-16(12)\n\t" /* save tocptr */ \ "ld 2,-8(12)\n\t" /* use nraddr's tocptr */ \ "ld 3, 8(12)\n\t" /* arg1->r3 */ \ "ld 4, 16(12)\n\t" /* arg2->r4 */ \ "ld 12, 0(12)\n\t" /* target->r12 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R12 \ "mr 12,%1\n\t" \ "mr %0,3\n\t" \ "ld 2,-16(12)\n\t" /* restore tocptr */ \ VALGRIND_RESTORE_STACK \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+3]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2+1] = (unsigned long)arg1; \ _argvec[2+2] = (unsigned long)arg2; \ _argvec[2+3] = (unsigned long)arg3; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 12,%1\n\t" \ "std 2,-16(12)\n\t" /* save tocptr */ \ "ld 2,-8(12)\n\t" /* use nraddr's tocptr */ \ "ld 3, 8(12)\n\t" /* arg1->r3 */ \ "ld 4, 16(12)\n\t" /* arg2->r4 */ \ "ld 5, 24(12)\n\t" /* arg3->r5 */ \ "ld 12, 0(12)\n\t" /* target->r12 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R12 \ "mr 12,%1\n\t" \ "mr %0,3\n\t" \ "ld 2,-16(12)\n\t" /* restore tocptr */ \ VALGRIND_RESTORE_STACK \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+4]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2+1] = (unsigned long)arg1; \ _argvec[2+2] = (unsigned long)arg2; \ _argvec[2+3] = (unsigned long)arg3; \ _argvec[2+4] = (unsigned long)arg4; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 12,%1\n\t" \ "std 2,-16(12)\n\t" /* save tocptr */ \ "ld 2,-8(12)\n\t" /* use nraddr's tocptr */ \ "ld 3, 8(12)\n\t" /* arg1->r3 */ \ "ld 4, 16(12)\n\t" /* arg2->r4 */ \ "ld 5, 24(12)\n\t" /* arg3->r5 */ \ "ld 6, 32(12)\n\t" /* arg4->r6 */ \ "ld 12, 0(12)\n\t" /* target->r12 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R12 \ "mr 12,%1\n\t" \ "mr %0,3\n\t" \ "ld 2,-16(12)\n\t" /* restore tocptr */ \ VALGRIND_RESTORE_STACK \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+5]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2+1] = (unsigned long)arg1; \ _argvec[2+2] = (unsigned long)arg2; \ _argvec[2+3] = (unsigned long)arg3; \ _argvec[2+4] = (unsigned long)arg4; \ _argvec[2+5] = (unsigned long)arg5; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 12,%1\n\t" \ "std 2,-16(12)\n\t" /* save tocptr */ \ "ld 2,-8(12)\n\t" /* use nraddr's tocptr */ \ "ld 3, 8(12)\n\t" /* arg1->r3 */ \ "ld 4, 16(12)\n\t" /* arg2->r4 */ \ "ld 5, 24(12)\n\t" /* arg3->r5 */ \ "ld 6, 32(12)\n\t" /* arg4->r6 */ \ "ld 7, 40(12)\n\t" /* arg5->r7 */ \ "ld 12, 0(12)\n\t" /* target->r12 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R12 \ "mr 12,%1\n\t" \ "mr %0,3\n\t" \ "ld 2,-16(12)\n\t" /* restore tocptr */ \ VALGRIND_RESTORE_STACK \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+6]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2+1] = (unsigned long)arg1; \ _argvec[2+2] = (unsigned long)arg2; \ _argvec[2+3] = (unsigned long)arg3; \ _argvec[2+4] = (unsigned long)arg4; \ _argvec[2+5] = (unsigned long)arg5; \ _argvec[2+6] = (unsigned long)arg6; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 12,%1\n\t" \ "std 2,-16(12)\n\t" /* save tocptr */ \ "ld 2,-8(12)\n\t" /* use nraddr's tocptr */ \ "ld 3, 8(12)\n\t" /* arg1->r3 */ \ "ld 4, 16(12)\n\t" /* arg2->r4 */ \ "ld 5, 24(12)\n\t" /* arg3->r5 */ \ "ld 6, 32(12)\n\t" /* arg4->r6 */ \ "ld 7, 40(12)\n\t" /* arg5->r7 */ \ "ld 8, 48(12)\n\t" /* arg6->r8 */ \ "ld 12, 0(12)\n\t" /* target->r12 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R12 \ "mr 12,%1\n\t" \ "mr %0,3\n\t" \ "ld 2,-16(12)\n\t" /* restore tocptr */ \ VALGRIND_RESTORE_STACK \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+7]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2+1] = (unsigned long)arg1; \ _argvec[2+2] = (unsigned long)arg2; \ _argvec[2+3] = (unsigned long)arg3; \ _argvec[2+4] = (unsigned long)arg4; \ _argvec[2+5] = (unsigned long)arg5; \ _argvec[2+6] = (unsigned long)arg6; \ _argvec[2+7] = (unsigned long)arg7; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 12,%1\n\t" \ "std 2,-16(12)\n\t" /* save tocptr */ \ "ld 2,-8(12)\n\t" /* use nraddr's tocptr */ \ "ld 3, 8(12)\n\t" /* arg1->r3 */ \ "ld 4, 16(12)\n\t" /* arg2->r4 */ \ "ld 5, 24(12)\n\t" /* arg3->r5 */ \ "ld 6, 32(12)\n\t" /* arg4->r6 */ \ "ld 7, 40(12)\n\t" /* arg5->r7 */ \ "ld 8, 48(12)\n\t" /* arg6->r8 */ \ "ld 9, 56(12)\n\t" /* arg7->r9 */ \ "ld 12, 0(12)\n\t" /* target->r12 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R12 \ "mr 12,%1\n\t" \ "mr %0,3\n\t" \ "ld 2,-16(12)\n\t" /* restore tocptr */ \ VALGRIND_RESTORE_STACK \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+8]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2+1] = (unsigned long)arg1; \ _argvec[2+2] = (unsigned long)arg2; \ _argvec[2+3] = (unsigned long)arg3; \ _argvec[2+4] = (unsigned long)arg4; \ _argvec[2+5] = (unsigned long)arg5; \ _argvec[2+6] = (unsigned long)arg6; \ _argvec[2+7] = (unsigned long)arg7; \ _argvec[2+8] = (unsigned long)arg8; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 12,%1\n\t" \ "std 2,-16(12)\n\t" /* save tocptr */ \ "ld 2,-8(12)\n\t" /* use nraddr's tocptr */ \ "ld 3, 8(12)\n\t" /* arg1->r3 */ \ "ld 4, 16(12)\n\t" /* arg2->r4 */ \ "ld 5, 24(12)\n\t" /* arg3->r5 */ \ "ld 6, 32(12)\n\t" /* arg4->r6 */ \ "ld 7, 40(12)\n\t" /* arg5->r7 */ \ "ld 8, 48(12)\n\t" /* arg6->r8 */ \ "ld 9, 56(12)\n\t" /* arg7->r9 */ \ "ld 10, 64(12)\n\t" /* arg8->r10 */ \ "ld 12, 0(12)\n\t" /* target->r12 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R12 \ "mr 12,%1\n\t" \ "mr %0,3\n\t" \ "ld 2,-16(12)\n\t" /* restore tocptr */ \ VALGRIND_RESTORE_STACK \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+9]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2+1] = (unsigned long)arg1; \ _argvec[2+2] = (unsigned long)arg2; \ _argvec[2+3] = (unsigned long)arg3; \ _argvec[2+4] = (unsigned long)arg4; \ _argvec[2+5] = (unsigned long)arg5; \ _argvec[2+6] = (unsigned long)arg6; \ _argvec[2+7] = (unsigned long)arg7; \ _argvec[2+8] = (unsigned long)arg8; \ _argvec[2+9] = (unsigned long)arg9; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 12,%1\n\t" \ "std 2,-16(12)\n\t" /* save tocptr */ \ "ld 2,-8(12)\n\t" /* use nraddr's tocptr */ \ "addi 1,1,-128\n\t" /* expand stack frame */ \ /* arg9 */ \ "ld 3,72(12)\n\t" \ "std 3,96(1)\n\t" \ /* args1-8 */ \ "ld 3, 8(12)\n\t" /* arg1->r3 */ \ "ld 4, 16(12)\n\t" /* arg2->r4 */ \ "ld 5, 24(12)\n\t" /* arg3->r5 */ \ "ld 6, 32(12)\n\t" /* arg4->r6 */ \ "ld 7, 40(12)\n\t" /* arg5->r7 */ \ "ld 8, 48(12)\n\t" /* arg6->r8 */ \ "ld 9, 56(12)\n\t" /* arg7->r9 */ \ "ld 10, 64(12)\n\t" /* arg8->r10 */ \ "ld 12, 0(12)\n\t" /* target->r12 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R12 \ "mr 12,%1\n\t" \ "mr %0,3\n\t" \ "ld 2,-16(12)\n\t" /* restore tocptr */ \ VALGRIND_RESTORE_STACK \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9,arg10) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+10]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2+1] = (unsigned long)arg1; \ _argvec[2+2] = (unsigned long)arg2; \ _argvec[2+3] = (unsigned long)arg3; \ _argvec[2+4] = (unsigned long)arg4; \ _argvec[2+5] = (unsigned long)arg5; \ _argvec[2+6] = (unsigned long)arg6; \ _argvec[2+7] = (unsigned long)arg7; \ _argvec[2+8] = (unsigned long)arg8; \ _argvec[2+9] = (unsigned long)arg9; \ _argvec[2+10] = (unsigned long)arg10; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 12,%1\n\t" \ "std 2,-16(12)\n\t" /* save tocptr */ \ "ld 2,-8(12)\n\t" /* use nraddr's tocptr */ \ "addi 1,1,-128\n\t" /* expand stack frame */ \ /* arg10 */ \ "ld 3,80(12)\n\t" \ "std 3,104(1)\n\t" \ /* arg9 */ \ "ld 3,72(12)\n\t" \ "std 3,96(1)\n\t" \ /* args1-8 */ \ "ld 3, 8(12)\n\t" /* arg1->r3 */ \ "ld 4, 16(12)\n\t" /* arg2->r4 */ \ "ld 5, 24(12)\n\t" /* arg3->r5 */ \ "ld 6, 32(12)\n\t" /* arg4->r6 */ \ "ld 7, 40(12)\n\t" /* arg5->r7 */ \ "ld 8, 48(12)\n\t" /* arg6->r8 */ \ "ld 9, 56(12)\n\t" /* arg7->r9 */ \ "ld 10, 64(12)\n\t" /* arg8->r10 */ \ "ld 12, 0(12)\n\t" /* target->r12 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R12 \ "mr 12,%1\n\t" \ "mr %0,3\n\t" \ "ld 2,-16(12)\n\t" /* restore tocptr */ \ VALGRIND_RESTORE_STACK \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9,arg10,arg11) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+11]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2+1] = (unsigned long)arg1; \ _argvec[2+2] = (unsigned long)arg2; \ _argvec[2+3] = (unsigned long)arg3; \ _argvec[2+4] = (unsigned long)arg4; \ _argvec[2+5] = (unsigned long)arg5; \ _argvec[2+6] = (unsigned long)arg6; \ _argvec[2+7] = (unsigned long)arg7; \ _argvec[2+8] = (unsigned long)arg8; \ _argvec[2+9] = (unsigned long)arg9; \ _argvec[2+10] = (unsigned long)arg10; \ _argvec[2+11] = (unsigned long)arg11; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 12,%1\n\t" \ "std 2,-16(12)\n\t" /* save tocptr */ \ "ld 2,-8(12)\n\t" /* use nraddr's tocptr */ \ "addi 1,1,-144\n\t" /* expand stack frame */ \ /* arg11 */ \ "ld 3,88(12)\n\t" \ "std 3,112(1)\n\t" \ /* arg10 */ \ "ld 3,80(12)\n\t" \ "std 3,104(1)\n\t" \ /* arg9 */ \ "ld 3,72(12)\n\t" \ "std 3,96(1)\n\t" \ /* args1-8 */ \ "ld 3, 8(12)\n\t" /* arg1->r3 */ \ "ld 4, 16(12)\n\t" /* arg2->r4 */ \ "ld 5, 24(12)\n\t" /* arg3->r5 */ \ "ld 6, 32(12)\n\t" /* arg4->r6 */ \ "ld 7, 40(12)\n\t" /* arg5->r7 */ \ "ld 8, 48(12)\n\t" /* arg6->r8 */ \ "ld 9, 56(12)\n\t" /* arg7->r9 */ \ "ld 10, 64(12)\n\t" /* arg8->r10 */ \ "ld 12, 0(12)\n\t" /* target->r12 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R12 \ "mr 12,%1\n\t" \ "mr %0,3\n\t" \ "ld 2,-16(12)\n\t" /* restore tocptr */ \ VALGRIND_RESTORE_STACK \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9,arg10,arg11,arg12) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+12]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2+1] = (unsigned long)arg1; \ _argvec[2+2] = (unsigned long)arg2; \ _argvec[2+3] = (unsigned long)arg3; \ _argvec[2+4] = (unsigned long)arg4; \ _argvec[2+5] = (unsigned long)arg5; \ _argvec[2+6] = (unsigned long)arg6; \ _argvec[2+7] = (unsigned long)arg7; \ _argvec[2+8] = (unsigned long)arg8; \ _argvec[2+9] = (unsigned long)arg9; \ _argvec[2+10] = (unsigned long)arg10; \ _argvec[2+11] = (unsigned long)arg11; \ _argvec[2+12] = (unsigned long)arg12; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 12,%1\n\t" \ "std 2,-16(12)\n\t" /* save tocptr */ \ "ld 2,-8(12)\n\t" /* use nraddr's tocptr */ \ "addi 1,1,-144\n\t" /* expand stack frame */ \ /* arg12 */ \ "ld 3,96(12)\n\t" \ "std 3,120(1)\n\t" \ /* arg11 */ \ "ld 3,88(12)\n\t" \ "std 3,112(1)\n\t" \ /* arg10 */ \ "ld 3,80(12)\n\t" \ "std 3,104(1)\n\t" \ /* arg9 */ \ "ld 3,72(12)\n\t" \ "std 3,96(1)\n\t" \ /* args1-8 */ \ "ld 3, 8(12)\n\t" /* arg1->r3 */ \ "ld 4, 16(12)\n\t" /* arg2->r4 */ \ "ld 5, 24(12)\n\t" /* arg3->r5 */ \ "ld 6, 32(12)\n\t" /* arg4->r6 */ \ "ld 7, 40(12)\n\t" /* arg5->r7 */ \ "ld 8, 48(12)\n\t" /* arg6->r8 */ \ "ld 9, 56(12)\n\t" /* arg7->r9 */ \ "ld 10, 64(12)\n\t" /* arg8->r10 */ \ "ld 12, 0(12)\n\t" /* target->r12 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R12 \ "mr 12,%1\n\t" \ "mr %0,3\n\t" \ "ld 2,-16(12)\n\t" /* restore tocptr */ \ VALGRIND_RESTORE_STACK \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #endif /* PLAT_ppc64le_linux */ /* ------------------------- arm-linux ------------------------- */ #if defined(PLAT_arm_linux) /* These regs are trashed by the hidden call. */ #define __CALLER_SAVED_REGS "r0", "r1", "r2", "r3","r4", "r12", "r14" /* Macros to save and align the stack before making a function call and restore it afterwards as gcc may not keep the stack pointer aligned if it doesn't realise calls are being made to other functions. */ /* This is a bit tricky. We store the original stack pointer in r10 as it is callee-saves. gcc doesn't allow the use of r11 for some reason. Also, we can't directly "bic" the stack pointer in thumb mode since r13 isn't an allowed register number in that context. So use r4 as a temporary, since that is about to get trashed anyway, just after each use of this macro. Side effect is we need to be very careful about any future changes, since VALGRIND_ALIGN_STACK simply assumes r4 is usable. */ #define VALGRIND_ALIGN_STACK \ "mov r10, sp\n\t" \ "mov r4, sp\n\t" \ "bic r4, r4, #7\n\t" \ "mov sp, r4\n\t" #define VALGRIND_RESTORE_STACK \ "mov sp, r10\n\t" /* These CALL_FN_ macros assume that on arm-linux, sizeof(unsigned long) == 4. */ #define CALL_FN_W_v(lval, orig) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[1]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "ldr r4, [%1] \n\t" /* target->r4 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ VALGRIND_RESTORE_STACK \ "mov %0, r0\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r10" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_W(lval, orig, arg1) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[2]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "ldr r0, [%1, #4] \n\t" \ "ldr r4, [%1] \n\t" /* target->r4 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ VALGRIND_RESTORE_STACK \ "mov %0, r0\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r10" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WW(lval, orig, arg1,arg2) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "ldr r0, [%1, #4] \n\t" \ "ldr r1, [%1, #8] \n\t" \ "ldr r4, [%1] \n\t" /* target->r4 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ VALGRIND_RESTORE_STACK \ "mov %0, r0\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r10" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[4]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "ldr r0, [%1, #4] \n\t" \ "ldr r1, [%1, #8] \n\t" \ "ldr r2, [%1, #12] \n\t" \ "ldr r4, [%1] \n\t" /* target->r4 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ VALGRIND_RESTORE_STACK \ "mov %0, r0\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r10" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[5]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "ldr r0, [%1, #4] \n\t" \ "ldr r1, [%1, #8] \n\t" \ "ldr r2, [%1, #12] \n\t" \ "ldr r3, [%1, #16] \n\t" \ "ldr r4, [%1] \n\t" /* target->r4 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ VALGRIND_RESTORE_STACK \ "mov %0, r0" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r10" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[6]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "sub sp, sp, #4 \n\t" \ "ldr r0, [%1, #20] \n\t" \ "push {r0} \n\t" \ "ldr r0, [%1, #4] \n\t" \ "ldr r1, [%1, #8] \n\t" \ "ldr r2, [%1, #12] \n\t" \ "ldr r3, [%1, #16] \n\t" \ "ldr r4, [%1] \n\t" /* target->r4 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ VALGRIND_RESTORE_STACK \ "mov %0, r0" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r10" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[7]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "ldr r0, [%1, #20] \n\t" \ "ldr r1, [%1, #24] \n\t" \ "push {r0, r1} \n\t" \ "ldr r0, [%1, #4] \n\t" \ "ldr r1, [%1, #8] \n\t" \ "ldr r2, [%1, #12] \n\t" \ "ldr r3, [%1, #16] \n\t" \ "ldr r4, [%1] \n\t" /* target->r4 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ VALGRIND_RESTORE_STACK \ "mov %0, r0" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r10" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[8]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "sub sp, sp, #4 \n\t" \ "ldr r0, [%1, #20] \n\t" \ "ldr r1, [%1, #24] \n\t" \ "ldr r2, [%1, #28] \n\t" \ "push {r0, r1, r2} \n\t" \ "ldr r0, [%1, #4] \n\t" \ "ldr r1, [%1, #8] \n\t" \ "ldr r2, [%1, #12] \n\t" \ "ldr r3, [%1, #16] \n\t" \ "ldr r4, [%1] \n\t" /* target->r4 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ VALGRIND_RESTORE_STACK \ "mov %0, r0" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r10" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[9]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "ldr r0, [%1, #20] \n\t" \ "ldr r1, [%1, #24] \n\t" \ "ldr r2, [%1, #28] \n\t" \ "ldr r3, [%1, #32] \n\t" \ "push {r0, r1, r2, r3} \n\t" \ "ldr r0, [%1, #4] \n\t" \ "ldr r1, [%1, #8] \n\t" \ "ldr r2, [%1, #12] \n\t" \ "ldr r3, [%1, #16] \n\t" \ "ldr r4, [%1] \n\t" /* target->r4 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ VALGRIND_RESTORE_STACK \ "mov %0, r0" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r10" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[10]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ _argvec[9] = (unsigned long)(arg9); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "sub sp, sp, #4 \n\t" \ "ldr r0, [%1, #20] \n\t" \ "ldr r1, [%1, #24] \n\t" \ "ldr r2, [%1, #28] \n\t" \ "ldr r3, [%1, #32] \n\t" \ "ldr r4, [%1, #36] \n\t" \ "push {r0, r1, r2, r3, r4} \n\t" \ "ldr r0, [%1, #4] \n\t" \ "ldr r1, [%1, #8] \n\t" \ "ldr r2, [%1, #12] \n\t" \ "ldr r3, [%1, #16] \n\t" \ "ldr r4, [%1] \n\t" /* target->r4 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ VALGRIND_RESTORE_STACK \ "mov %0, r0" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r10" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9,arg10) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[11]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ _argvec[9] = (unsigned long)(arg9); \ _argvec[10] = (unsigned long)(arg10); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "ldr r0, [%1, #40] \n\t" \ "push {r0} \n\t" \ "ldr r0, [%1, #20] \n\t" \ "ldr r1, [%1, #24] \n\t" \ "ldr r2, [%1, #28] \n\t" \ "ldr r3, [%1, #32] \n\t" \ "ldr r4, [%1, #36] \n\t" \ "push {r0, r1, r2, r3, r4} \n\t" \ "ldr r0, [%1, #4] \n\t" \ "ldr r1, [%1, #8] \n\t" \ "ldr r2, [%1, #12] \n\t" \ "ldr r3, [%1, #16] \n\t" \ "ldr r4, [%1] \n\t" /* target->r4 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ VALGRIND_RESTORE_STACK \ "mov %0, r0" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r10" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5, \ arg6,arg7,arg8,arg9,arg10, \ arg11) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[12]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ _argvec[9] = (unsigned long)(arg9); \ _argvec[10] = (unsigned long)(arg10); \ _argvec[11] = (unsigned long)(arg11); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "sub sp, sp, #4 \n\t" \ "ldr r0, [%1, #40] \n\t" \ "ldr r1, [%1, #44] \n\t" \ "push {r0, r1} \n\t" \ "ldr r0, [%1, #20] \n\t" \ "ldr r1, [%1, #24] \n\t" \ "ldr r2, [%1, #28] \n\t" \ "ldr r3, [%1, #32] \n\t" \ "ldr r4, [%1, #36] \n\t" \ "push {r0, r1, r2, r3, r4} \n\t" \ "ldr r0, [%1, #4] \n\t" \ "ldr r1, [%1, #8] \n\t" \ "ldr r2, [%1, #12] \n\t" \ "ldr r3, [%1, #16] \n\t" \ "ldr r4, [%1] \n\t" /* target->r4 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ VALGRIND_RESTORE_STACK \ "mov %0, r0" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r10" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5, \ arg6,arg7,arg8,arg9,arg10, \ arg11,arg12) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[13]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ _argvec[9] = (unsigned long)(arg9); \ _argvec[10] = (unsigned long)(arg10); \ _argvec[11] = (unsigned long)(arg11); \ _argvec[12] = (unsigned long)(arg12); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "ldr r0, [%1, #40] \n\t" \ "ldr r1, [%1, #44] \n\t" \ "ldr r2, [%1, #48] \n\t" \ "push {r0, r1, r2} \n\t" \ "ldr r0, [%1, #20] \n\t" \ "ldr r1, [%1, #24] \n\t" \ "ldr r2, [%1, #28] \n\t" \ "ldr r3, [%1, #32] \n\t" \ "ldr r4, [%1, #36] \n\t" \ "push {r0, r1, r2, r3, r4} \n\t" \ "ldr r0, [%1, #4] \n\t" \ "ldr r1, [%1, #8] \n\t" \ "ldr r2, [%1, #12] \n\t" \ "ldr r3, [%1, #16] \n\t" \ "ldr r4, [%1] \n\t" /* target->r4 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ VALGRIND_RESTORE_STACK \ "mov %0, r0" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r10" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #endif /* PLAT_arm_linux */ /* ------------------------ arm64-linux ------------------------ */ #if defined(PLAT_arm64_linux) /* These regs are trashed by the hidden call. */ #define __CALLER_SAVED_REGS \ "x0", "x1", "x2", "x3","x4", "x5", "x6", "x7", "x8", "x9", \ "x10", "x11", "x12", "x13", "x14", "x15", "x16", "x17", \ "x18", "x19", "x20", "x30", \ "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8", "v9", \ "v10", "v11", "v12", "v13", "v14", "v15", "v16", "v17", \ "v18", "v19", "v20", "v21", "v22", "v23", "v24", "v25", \ "v26", "v27", "v28", "v29", "v30", "v31" /* x21 is callee-saved, so we can use it to save and restore SP around the hidden call. */ #define VALGRIND_ALIGN_STACK \ "mov x21, sp\n\t" \ "bic sp, x21, #15\n\t" #define VALGRIND_RESTORE_STACK \ "mov sp, x21\n\t" /* These CALL_FN_ macros assume that on arm64-linux, sizeof(unsigned long) == 8. */ #define CALL_FN_W_v(lval, orig) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[1]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "ldr x8, [%1] \n\t" /* target->x8 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_X8 \ VALGRIND_RESTORE_STACK \ "mov %0, x0\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "x21" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_W(lval, orig, arg1) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[2]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "ldr x0, [%1, #8] \n\t" \ "ldr x8, [%1] \n\t" /* target->x8 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_X8 \ VALGRIND_RESTORE_STACK \ "mov %0, x0\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "x21" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WW(lval, orig, arg1,arg2) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "ldr x0, [%1, #8] \n\t" \ "ldr x1, [%1, #16] \n\t" \ "ldr x8, [%1] \n\t" /* target->x8 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_X8 \ VALGRIND_RESTORE_STACK \ "mov %0, x0\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "x21" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[4]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "ldr x0, [%1, #8] \n\t" \ "ldr x1, [%1, #16] \n\t" \ "ldr x2, [%1, #24] \n\t" \ "ldr x8, [%1] \n\t" /* target->x8 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_X8 \ VALGRIND_RESTORE_STACK \ "mov %0, x0\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "x21" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[5]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "ldr x0, [%1, #8] \n\t" \ "ldr x1, [%1, #16] \n\t" \ "ldr x2, [%1, #24] \n\t" \ "ldr x3, [%1, #32] \n\t" \ "ldr x8, [%1] \n\t" /* target->x8 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_X8 \ VALGRIND_RESTORE_STACK \ "mov %0, x0" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "x21" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[6]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "ldr x0, [%1, #8] \n\t" \ "ldr x1, [%1, #16] \n\t" \ "ldr x2, [%1, #24] \n\t" \ "ldr x3, [%1, #32] \n\t" \ "ldr x4, [%1, #40] \n\t" \ "ldr x8, [%1] \n\t" /* target->x8 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_X8 \ VALGRIND_RESTORE_STACK \ "mov %0, x0" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "x21" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[7]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "ldr x0, [%1, #8] \n\t" \ "ldr x1, [%1, #16] \n\t" \ "ldr x2, [%1, #24] \n\t" \ "ldr x3, [%1, #32] \n\t" \ "ldr x4, [%1, #40] \n\t" \ "ldr x5, [%1, #48] \n\t" \ "ldr x8, [%1] \n\t" /* target->x8 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_X8 \ VALGRIND_RESTORE_STACK \ "mov %0, x0" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "x21" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[8]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "ldr x0, [%1, #8] \n\t" \ "ldr x1, [%1, #16] \n\t" \ "ldr x2, [%1, #24] \n\t" \ "ldr x3, [%1, #32] \n\t" \ "ldr x4, [%1, #40] \n\t" \ "ldr x5, [%1, #48] \n\t" \ "ldr x6, [%1, #56] \n\t" \ "ldr x8, [%1] \n\t" /* target->x8 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_X8 \ VALGRIND_RESTORE_STACK \ "mov %0, x0" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "x21" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[9]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "ldr x0, [%1, #8] \n\t" \ "ldr x1, [%1, #16] \n\t" \ "ldr x2, [%1, #24] \n\t" \ "ldr x3, [%1, #32] \n\t" \ "ldr x4, [%1, #40] \n\t" \ "ldr x5, [%1, #48] \n\t" \ "ldr x6, [%1, #56] \n\t" \ "ldr x7, [%1, #64] \n\t" \ "ldr x8, [%1] \n\t" /* target->x8 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_X8 \ VALGRIND_RESTORE_STACK \ "mov %0, x0" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "x21" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[10]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ _argvec[9] = (unsigned long)(arg9); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "sub sp, sp, #0x20 \n\t" \ "ldr x0, [%1, #8] \n\t" \ "ldr x1, [%1, #16] \n\t" \ "ldr x2, [%1, #24] \n\t" \ "ldr x3, [%1, #32] \n\t" \ "ldr x4, [%1, #40] \n\t" \ "ldr x5, [%1, #48] \n\t" \ "ldr x6, [%1, #56] \n\t" \ "ldr x7, [%1, #64] \n\t" \ "ldr x8, [%1, #72] \n\t" \ "str x8, [sp, #0] \n\t" \ "ldr x8, [%1] \n\t" /* target->x8 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_X8 \ VALGRIND_RESTORE_STACK \ "mov %0, x0" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "x21" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9,arg10) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[11]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ _argvec[9] = (unsigned long)(arg9); \ _argvec[10] = (unsigned long)(arg10); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "sub sp, sp, #0x20 \n\t" \ "ldr x0, [%1, #8] \n\t" \ "ldr x1, [%1, #16] \n\t" \ "ldr x2, [%1, #24] \n\t" \ "ldr x3, [%1, #32] \n\t" \ "ldr x4, [%1, #40] \n\t" \ "ldr x5, [%1, #48] \n\t" \ "ldr x6, [%1, #56] \n\t" \ "ldr x7, [%1, #64] \n\t" \ "ldr x8, [%1, #72] \n\t" \ "str x8, [sp, #0] \n\t" \ "ldr x8, [%1, #80] \n\t" \ "str x8, [sp, #8] \n\t" \ "ldr x8, [%1] \n\t" /* target->x8 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_X8 \ VALGRIND_RESTORE_STACK \ "mov %0, x0" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "x21" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9,arg10,arg11) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[12]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ _argvec[9] = (unsigned long)(arg9); \ _argvec[10] = (unsigned long)(arg10); \ _argvec[11] = (unsigned long)(arg11); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "sub sp, sp, #0x30 \n\t" \ "ldr x0, [%1, #8] \n\t" \ "ldr x1, [%1, #16] \n\t" \ "ldr x2, [%1, #24] \n\t" \ "ldr x3, [%1, #32] \n\t" \ "ldr x4, [%1, #40] \n\t" \ "ldr x5, [%1, #48] \n\t" \ "ldr x6, [%1, #56] \n\t" \ "ldr x7, [%1, #64] \n\t" \ "ldr x8, [%1, #72] \n\t" \ "str x8, [sp, #0] \n\t" \ "ldr x8, [%1, #80] \n\t" \ "str x8, [sp, #8] \n\t" \ "ldr x8, [%1, #88] \n\t" \ "str x8, [sp, #16] \n\t" \ "ldr x8, [%1] \n\t" /* target->x8 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_X8 \ VALGRIND_RESTORE_STACK \ "mov %0, x0" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "x21" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9,arg10,arg11, \ arg12) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[13]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ _argvec[9] = (unsigned long)(arg9); \ _argvec[10] = (unsigned long)(arg10); \ _argvec[11] = (unsigned long)(arg11); \ _argvec[12] = (unsigned long)(arg12); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "sub sp, sp, #0x30 \n\t" \ "ldr x0, [%1, #8] \n\t" \ "ldr x1, [%1, #16] \n\t" \ "ldr x2, [%1, #24] \n\t" \ "ldr x3, [%1, #32] \n\t" \ "ldr x4, [%1, #40] \n\t" \ "ldr x5, [%1, #48] \n\t" \ "ldr x6, [%1, #56] \n\t" \ "ldr x7, [%1, #64] \n\t" \ "ldr x8, [%1, #72] \n\t" \ "str x8, [sp, #0] \n\t" \ "ldr x8, [%1, #80] \n\t" \ "str x8, [sp, #8] \n\t" \ "ldr x8, [%1, #88] \n\t" \ "str x8, [sp, #16] \n\t" \ "ldr x8, [%1, #96] \n\t" \ "str x8, [sp, #24] \n\t" \ "ldr x8, [%1] \n\t" /* target->x8 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_X8 \ VALGRIND_RESTORE_STACK \ "mov %0, x0" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "x21" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #endif /* PLAT_arm64_linux */ /* ------------------------- s390x-linux ------------------------- */ #if defined(PLAT_s390x_linux) /* Similar workaround as amd64 (see above), but we use r11 as frame pointer and save the old r11 in r7. r11 might be used for argvec, therefore we copy argvec in r1 since r1 is clobbered after the call anyway. */ #if defined(__GNUC__) && defined(__GCC_HAVE_DWARF2_CFI_ASM) # define __FRAME_POINTER \ ,"d"(__builtin_dwarf_cfa()) # define VALGRIND_CFI_PROLOGUE \ ".cfi_remember_state\n\t" \ "lgr 1,%1\n\t" /* copy the argvec pointer in r1 */ \ "lgr 7,11\n\t" \ "lgr 11,%2\n\t" \ ".cfi_def_cfa r11, 0\n\t" # define VALGRIND_CFI_EPILOGUE \ "lgr 11, 7\n\t" \ ".cfi_restore_state\n\t" #else # define __FRAME_POINTER # define VALGRIND_CFI_PROLOGUE \ "lgr 1,%1\n\t" # define VALGRIND_CFI_EPILOGUE #endif /* Nb: On s390 the stack pointer is properly aligned *at all times* according to the s390 GCC maintainer. (The ABI specification is not precise in this regard.) Therefore, VALGRIND_ALIGN_STACK and VALGRIND_RESTORE_STACK are not defined here. */ /* These regs are trashed by the hidden call. Note that we overwrite r14 in s390_irgen_noredir (VEX/priv/guest_s390_irgen.c) to give the function a proper return address. All others are ABI defined call clobbers. */ #if defined(__VX__) || defined(__S390_VX__) #define __CALLER_SAVED_REGS "0", "1", "2", "3", "4", "5", "14", \ "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", \ "v8", "v9", "v10", "v11", "v12", "v13", "v14", "v15", \ "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23", \ "v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31" #else #define __CALLER_SAVED_REGS "0", "1", "2", "3", "4", "5", "14", \ "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7" #endif /* Nb: Although r11 is modified in the asm snippets below (inside VALGRIND_CFI_PROLOGUE) it is not listed in the clobber section, for two reasons: (1) r11 is restored in VALGRIND_CFI_EPILOGUE, so effectively it is not modified (2) GCC will complain that r11 cannot appear inside a clobber section, when compiled with -O -fno-omit-frame-pointer */ #define CALL_FN_W_v(lval, orig) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[1]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ __asm__ volatile( \ VALGRIND_CFI_PROLOGUE \ "aghi 15,-160\n\t" \ "lg 1, 0(1)\n\t" /* target->r1 */ \ VALGRIND_CALL_NOREDIR_R1 \ "aghi 15,160\n\t" \ VALGRIND_CFI_EPILOGUE \ "lgr %0, 2\n\t" \ : /*out*/ "=d" (_res) \ : /*in*/ "d" (&_argvec[0]) __FRAME_POINTER \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"7" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) /* The call abi has the arguments in r2-r6 and stack */ #define CALL_FN_W_W(lval, orig, arg1) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[2]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)arg1; \ __asm__ volatile( \ VALGRIND_CFI_PROLOGUE \ "aghi 15,-160\n\t" \ "lg 2, 8(1)\n\t" \ "lg 1, 0(1)\n\t" \ VALGRIND_CALL_NOREDIR_R1 \ "aghi 15,160\n\t" \ VALGRIND_CFI_EPILOGUE \ "lgr %0, 2\n\t" \ : /*out*/ "=d" (_res) \ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"7" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WW(lval, orig, arg1, arg2) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)arg1; \ _argvec[2] = (unsigned long)arg2; \ __asm__ volatile( \ VALGRIND_CFI_PROLOGUE \ "aghi 15,-160\n\t" \ "lg 2, 8(1)\n\t" \ "lg 3,16(1)\n\t" \ "lg 1, 0(1)\n\t" \ VALGRIND_CALL_NOREDIR_R1 \ "aghi 15,160\n\t" \ VALGRIND_CFI_EPILOGUE \ "lgr %0, 2\n\t" \ : /*out*/ "=d" (_res) \ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"7" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WWW(lval, orig, arg1, arg2, arg3) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[4]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)arg1; \ _argvec[2] = (unsigned long)arg2; \ _argvec[3] = (unsigned long)arg3; \ __asm__ volatile( \ VALGRIND_CFI_PROLOGUE \ "aghi 15,-160\n\t" \ "lg 2, 8(1)\n\t" \ "lg 3,16(1)\n\t" \ "lg 4,24(1)\n\t" \ "lg 1, 0(1)\n\t" \ VALGRIND_CALL_NOREDIR_R1 \ "aghi 15,160\n\t" \ VALGRIND_CFI_EPILOGUE \ "lgr %0, 2\n\t" \ : /*out*/ "=d" (_res) \ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"7" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WWWW(lval, orig, arg1, arg2, arg3, arg4) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[5]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)arg1; \ _argvec[2] = (unsigned long)arg2; \ _argvec[3] = (unsigned long)arg3; \ _argvec[4] = (unsigned long)arg4; \ __asm__ volatile( \ VALGRIND_CFI_PROLOGUE \ "aghi 15,-160\n\t" \ "lg 2, 8(1)\n\t" \ "lg 3,16(1)\n\t" \ "lg 4,24(1)\n\t" \ "lg 5,32(1)\n\t" \ "lg 1, 0(1)\n\t" \ VALGRIND_CALL_NOREDIR_R1 \ "aghi 15,160\n\t" \ VALGRIND_CFI_EPILOGUE \ "lgr %0, 2\n\t" \ : /*out*/ "=d" (_res) \ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"7" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_5W(lval, orig, arg1, arg2, arg3, arg4, arg5) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[6]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)arg1; \ _argvec[2] = (unsigned long)arg2; \ _argvec[3] = (unsigned long)arg3; \ _argvec[4] = (unsigned long)arg4; \ _argvec[5] = (unsigned long)arg5; \ __asm__ volatile( \ VALGRIND_CFI_PROLOGUE \ "aghi 15,-160\n\t" \ "lg 2, 8(1)\n\t" \ "lg 3,16(1)\n\t" \ "lg 4,24(1)\n\t" \ "lg 5,32(1)\n\t" \ "lg 6,40(1)\n\t" \ "lg 1, 0(1)\n\t" \ VALGRIND_CALL_NOREDIR_R1 \ "aghi 15,160\n\t" \ VALGRIND_CFI_EPILOGUE \ "lgr %0, 2\n\t" \ : /*out*/ "=d" (_res) \ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"6","7" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_6W(lval, orig, arg1, arg2, arg3, arg4, arg5, \ arg6) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[7]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)arg1; \ _argvec[2] = (unsigned long)arg2; \ _argvec[3] = (unsigned long)arg3; \ _argvec[4] = (unsigned long)arg4; \ _argvec[5] = (unsigned long)arg5; \ _argvec[6] = (unsigned long)arg6; \ __asm__ volatile( \ VALGRIND_CFI_PROLOGUE \ "aghi 15,-168\n\t" \ "lg 2, 8(1)\n\t" \ "lg 3,16(1)\n\t" \ "lg 4,24(1)\n\t" \ "lg 5,32(1)\n\t" \ "lg 6,40(1)\n\t" \ "mvc 160(8,15), 48(1)\n\t" \ "lg 1, 0(1)\n\t" \ VALGRIND_CALL_NOREDIR_R1 \ "aghi 15,168\n\t" \ VALGRIND_CFI_EPILOGUE \ "lgr %0, 2\n\t" \ : /*out*/ "=d" (_res) \ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"6","7" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_7W(lval, orig, arg1, arg2, arg3, arg4, arg5, \ arg6, arg7) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[8]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)arg1; \ _argvec[2] = (unsigned long)arg2; \ _argvec[3] = (unsigned long)arg3; \ _argvec[4] = (unsigned long)arg4; \ _argvec[5] = (unsigned long)arg5; \ _argvec[6] = (unsigned long)arg6; \ _argvec[7] = (unsigned long)arg7; \ __asm__ volatile( \ VALGRIND_CFI_PROLOGUE \ "aghi 15,-176\n\t" \ "lg 2, 8(1)\n\t" \ "lg 3,16(1)\n\t" \ "lg 4,24(1)\n\t" \ "lg 5,32(1)\n\t" \ "lg 6,40(1)\n\t" \ "mvc 160(8,15), 48(1)\n\t" \ "mvc 168(8,15), 56(1)\n\t" \ "lg 1, 0(1)\n\t" \ VALGRIND_CALL_NOREDIR_R1 \ "aghi 15,176\n\t" \ VALGRIND_CFI_EPILOGUE \ "lgr %0, 2\n\t" \ : /*out*/ "=d" (_res) \ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"6","7" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_8W(lval, orig, arg1, arg2, arg3, arg4, arg5, \ arg6, arg7 ,arg8) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[9]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)arg1; \ _argvec[2] = (unsigned long)arg2; \ _argvec[3] = (unsigned long)arg3; \ _argvec[4] = (unsigned long)arg4; \ _argvec[5] = (unsigned long)arg5; \ _argvec[6] = (unsigned long)arg6; \ _argvec[7] = (unsigned long)arg7; \ _argvec[8] = (unsigned long)arg8; \ __asm__ volatile( \ VALGRIND_CFI_PROLOGUE \ "aghi 15,-184\n\t" \ "lg 2, 8(1)\n\t" \ "lg 3,16(1)\n\t" \ "lg 4,24(1)\n\t" \ "lg 5,32(1)\n\t" \ "lg 6,40(1)\n\t" \ "mvc 160(8,15), 48(1)\n\t" \ "mvc 168(8,15), 56(1)\n\t" \ "mvc 176(8,15), 64(1)\n\t" \ "lg 1, 0(1)\n\t" \ VALGRIND_CALL_NOREDIR_R1 \ "aghi 15,184\n\t" \ VALGRIND_CFI_EPILOGUE \ "lgr %0, 2\n\t" \ : /*out*/ "=d" (_res) \ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"6","7" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_9W(lval, orig, arg1, arg2, arg3, arg4, arg5, \ arg6, arg7 ,arg8, arg9) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[10]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)arg1; \ _argvec[2] = (unsigned long)arg2; \ _argvec[3] = (unsigned long)arg3; \ _argvec[4] = (unsigned long)arg4; \ _argvec[5] = (unsigned long)arg5; \ _argvec[6] = (unsigned long)arg6; \ _argvec[7] = (unsigned long)arg7; \ _argvec[8] = (unsigned long)arg8; \ _argvec[9] = (unsigned long)arg9; \ __asm__ volatile( \ VALGRIND_CFI_PROLOGUE \ "aghi 15,-192\n\t" \ "lg 2, 8(1)\n\t" \ "lg 3,16(1)\n\t" \ "lg 4,24(1)\n\t" \ "lg 5,32(1)\n\t" \ "lg 6,40(1)\n\t" \ "mvc 160(8,15), 48(1)\n\t" \ "mvc 168(8,15), 56(1)\n\t" \ "mvc 176(8,15), 64(1)\n\t" \ "mvc 184(8,15), 72(1)\n\t" \ "lg 1, 0(1)\n\t" \ VALGRIND_CALL_NOREDIR_R1 \ "aghi 15,192\n\t" \ VALGRIND_CFI_EPILOGUE \ "lgr %0, 2\n\t" \ : /*out*/ "=d" (_res) \ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"6","7" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_10W(lval, orig, arg1, arg2, arg3, arg4, arg5, \ arg6, arg7 ,arg8, arg9, arg10) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[11]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)arg1; \ _argvec[2] = (unsigned long)arg2; \ _argvec[3] = (unsigned long)arg3; \ _argvec[4] = (unsigned long)arg4; \ _argvec[5] = (unsigned long)arg5; \ _argvec[6] = (unsigned long)arg6; \ _argvec[7] = (unsigned long)arg7; \ _argvec[8] = (unsigned long)arg8; \ _argvec[9] = (unsigned long)arg9; \ _argvec[10] = (unsigned long)arg10; \ __asm__ volatile( \ VALGRIND_CFI_PROLOGUE \ "aghi 15,-200\n\t" \ "lg 2, 8(1)\n\t" \ "lg 3,16(1)\n\t" \ "lg 4,24(1)\n\t" \ "lg 5,32(1)\n\t" \ "lg 6,40(1)\n\t" \ "mvc 160(8,15), 48(1)\n\t" \ "mvc 168(8,15), 56(1)\n\t" \ "mvc 176(8,15), 64(1)\n\t" \ "mvc 184(8,15), 72(1)\n\t" \ "mvc 192(8,15), 80(1)\n\t" \ "lg 1, 0(1)\n\t" \ VALGRIND_CALL_NOREDIR_R1 \ "aghi 15,200\n\t" \ VALGRIND_CFI_EPILOGUE \ "lgr %0, 2\n\t" \ : /*out*/ "=d" (_res) \ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"6","7" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_11W(lval, orig, arg1, arg2, arg3, arg4, arg5, \ arg6, arg7 ,arg8, arg9, arg10, arg11) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[12]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)arg1; \ _argvec[2] = (unsigned long)arg2; \ _argvec[3] = (unsigned long)arg3; \ _argvec[4] = (unsigned long)arg4; \ _argvec[5] = (unsigned long)arg5; \ _argvec[6] = (unsigned long)arg6; \ _argvec[7] = (unsigned long)arg7; \ _argvec[8] = (unsigned long)arg8; \ _argvec[9] = (unsigned long)arg9; \ _argvec[10] = (unsigned long)arg10; \ _argvec[11] = (unsigned long)arg11; \ __asm__ volatile( \ VALGRIND_CFI_PROLOGUE \ "aghi 15,-208\n\t" \ "lg 2, 8(1)\n\t" \ "lg 3,16(1)\n\t" \ "lg 4,24(1)\n\t" \ "lg 5,32(1)\n\t" \ "lg 6,40(1)\n\t" \ "mvc 160(8,15), 48(1)\n\t" \ "mvc 168(8,15), 56(1)\n\t" \ "mvc 176(8,15), 64(1)\n\t" \ "mvc 184(8,15), 72(1)\n\t" \ "mvc 192(8,15), 80(1)\n\t" \ "mvc 200(8,15), 88(1)\n\t" \ "lg 1, 0(1)\n\t" \ VALGRIND_CALL_NOREDIR_R1 \ "aghi 15,208\n\t" \ VALGRIND_CFI_EPILOGUE \ "lgr %0, 2\n\t" \ : /*out*/ "=d" (_res) \ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"6","7" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_12W(lval, orig, arg1, arg2, arg3, arg4, arg5, \ arg6, arg7 ,arg8, arg9, arg10, arg11, arg12)\ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[13]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)arg1; \ _argvec[2] = (unsigned long)arg2; \ _argvec[3] = (unsigned long)arg3; \ _argvec[4] = (unsigned long)arg4; \ _argvec[5] = (unsigned long)arg5; \ _argvec[6] = (unsigned long)arg6; \ _argvec[7] = (unsigned long)arg7; \ _argvec[8] = (unsigned long)arg8; \ _argvec[9] = (unsigned long)arg9; \ _argvec[10] = (unsigned long)arg10; \ _argvec[11] = (unsigned long)arg11; \ _argvec[12] = (unsigned long)arg12; \ __asm__ volatile( \ VALGRIND_CFI_PROLOGUE \ "aghi 15,-216\n\t" \ "lg 2, 8(1)\n\t" \ "lg 3,16(1)\n\t" \ "lg 4,24(1)\n\t" \ "lg 5,32(1)\n\t" \ "lg 6,40(1)\n\t" \ "mvc 160(8,15), 48(1)\n\t" \ "mvc 168(8,15), 56(1)\n\t" \ "mvc 176(8,15), 64(1)\n\t" \ "mvc 184(8,15), 72(1)\n\t" \ "mvc 192(8,15), 80(1)\n\t" \ "mvc 200(8,15), 88(1)\n\t" \ "mvc 208(8,15), 96(1)\n\t" \ "lg 1, 0(1)\n\t" \ VALGRIND_CALL_NOREDIR_R1 \ "aghi 15,216\n\t" \ VALGRIND_CFI_EPILOGUE \ "lgr %0, 2\n\t" \ : /*out*/ "=d" (_res) \ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"6","7" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #endif /* PLAT_s390x_linux */ /* ------------------------- mips32-linux ----------------------- */ #if defined(PLAT_mips32_linux) /* These regs are trashed by the hidden call. */ #define __CALLER_SAVED_REGS "$2", "$3", "$4", "$5", "$6", \ "$7", "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15", "$24", \ "$25", "$31" /* These CALL_FN_ macros assume that on mips-linux, sizeof(unsigned long) == 4. */ #define CALL_FN_W_v(lval, orig) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[1]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ __asm__ volatile( \ "subu $29, $29, 8 \n\t" \ "sw $28, 0($29) \n\t" \ "sw $31, 4($29) \n\t" \ "subu $29, $29, 16 \n\t" \ "lw $25, 0(%1) \n\t" /* target->t9 */ \ VALGRIND_CALL_NOREDIR_T9 \ "addu $29, $29, 16\n\t" \ "lw $28, 0($29) \n\t" \ "lw $31, 4($29) \n\t" \ "addu $29, $29, 8 \n\t" \ "move %0, $2\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_W(lval, orig, arg1) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[2]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ __asm__ volatile( \ "subu $29, $29, 8 \n\t" \ "sw $28, 0($29) \n\t" \ "sw $31, 4($29) \n\t" \ "subu $29, $29, 16 \n\t" \ "lw $4, 4(%1) \n\t" /* arg1*/ \ "lw $25, 0(%1) \n\t" /* target->t9 */ \ VALGRIND_CALL_NOREDIR_T9 \ "addu $29, $29, 16 \n\t" \ "lw $28, 0($29) \n\t" \ "lw $31, 4($29) \n\t" \ "addu $29, $29, 8 \n\t" \ "move %0, $2\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WW(lval, orig, arg1,arg2) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ __asm__ volatile( \ "subu $29, $29, 8 \n\t" \ "sw $28, 0($29) \n\t" \ "sw $31, 4($29) \n\t" \ "subu $29, $29, 16 \n\t" \ "lw $4, 4(%1) \n\t" \ "lw $5, 8(%1) \n\t" \ "lw $25, 0(%1) \n\t" /* target->t9 */ \ VALGRIND_CALL_NOREDIR_T9 \ "addu $29, $29, 16 \n\t" \ "lw $28, 0($29) \n\t" \ "lw $31, 4($29) \n\t" \ "addu $29, $29, 8 \n\t" \ "move %0, $2\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[4]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ __asm__ volatile( \ "subu $29, $29, 8 \n\t" \ "sw $28, 0($29) \n\t" \ "sw $31, 4($29) \n\t" \ "subu $29, $29, 16 \n\t" \ "lw $4, 4(%1) \n\t" \ "lw $5, 8(%1) \n\t" \ "lw $6, 12(%1) \n\t" \ "lw $25, 0(%1) \n\t" /* target->t9 */ \ VALGRIND_CALL_NOREDIR_T9 \ "addu $29, $29, 16 \n\t" \ "lw $28, 0($29) \n\t" \ "lw $31, 4($29) \n\t" \ "addu $29, $29, 8 \n\t" \ "move %0, $2\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[5]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ __asm__ volatile( \ "subu $29, $29, 8 \n\t" \ "sw $28, 0($29) \n\t" \ "sw $31, 4($29) \n\t" \ "subu $29, $29, 16 \n\t" \ "lw $4, 4(%1) \n\t" \ "lw $5, 8(%1) \n\t" \ "lw $6, 12(%1) \n\t" \ "lw $7, 16(%1) \n\t" \ "lw $25, 0(%1) \n\t" /* target->t9 */ \ VALGRIND_CALL_NOREDIR_T9 \ "addu $29, $29, 16 \n\t" \ "lw $28, 0($29) \n\t" \ "lw $31, 4($29) \n\t" \ "addu $29, $29, 8 \n\t" \ "move %0, $2\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[6]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ __asm__ volatile( \ "subu $29, $29, 8 \n\t" \ "sw $28, 0($29) \n\t" \ "sw $31, 4($29) \n\t" \ "lw $4, 20(%1) \n\t" \ "subu $29, $29, 24\n\t" \ "sw $4, 16($29) \n\t" \ "lw $4, 4(%1) \n\t" \ "lw $5, 8(%1) \n\t" \ "lw $6, 12(%1) \n\t" \ "lw $7, 16(%1) \n\t" \ "lw $25, 0(%1) \n\t" /* target->t9 */ \ VALGRIND_CALL_NOREDIR_T9 \ "addu $29, $29, 24 \n\t" \ "lw $28, 0($29) \n\t" \ "lw $31, 4($29) \n\t" \ "addu $29, $29, 8 \n\t" \ "move %0, $2\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[7]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ __asm__ volatile( \ "subu $29, $29, 8 \n\t" \ "sw $28, 0($29) \n\t" \ "sw $31, 4($29) \n\t" \ "lw $4, 20(%1) \n\t" \ "subu $29, $29, 32\n\t" \ "sw $4, 16($29) \n\t" \ "lw $4, 24(%1) \n\t" \ "nop\n\t" \ "sw $4, 20($29) \n\t" \ "lw $4, 4(%1) \n\t" \ "lw $5, 8(%1) \n\t" \ "lw $6, 12(%1) \n\t" \ "lw $7, 16(%1) \n\t" \ "lw $25, 0(%1) \n\t" /* target->t9 */ \ VALGRIND_CALL_NOREDIR_T9 \ "addu $29, $29, 32 \n\t" \ "lw $28, 0($29) \n\t" \ "lw $31, 4($29) \n\t" \ "addu $29, $29, 8 \n\t" \ "move %0, $2\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[8]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ __asm__ volatile( \ "subu $29, $29, 8 \n\t" \ "sw $28, 0($29) \n\t" \ "sw $31, 4($29) \n\t" \ "lw $4, 20(%1) \n\t" \ "subu $29, $29, 32\n\t" \ "sw $4, 16($29) \n\t" \ "lw $4, 24(%1) \n\t" \ "sw $4, 20($29) \n\t" \ "lw $4, 28(%1) \n\t" \ "sw $4, 24($29) \n\t" \ "lw $4, 4(%1) \n\t" \ "lw $5, 8(%1) \n\t" \ "lw $6, 12(%1) \n\t" \ "lw $7, 16(%1) \n\t" \ "lw $25, 0(%1) \n\t" /* target->t9 */ \ VALGRIND_CALL_NOREDIR_T9 \ "addu $29, $29, 32 \n\t" \ "lw $28, 0($29) \n\t" \ "lw $31, 4($29) \n\t" \ "addu $29, $29, 8 \n\t" \ "move %0, $2\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[9]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ __asm__ volatile( \ "subu $29, $29, 8 \n\t" \ "sw $28, 0($29) \n\t" \ "sw $31, 4($29) \n\t" \ "lw $4, 20(%1) \n\t" \ "subu $29, $29, 40\n\t" \ "sw $4, 16($29) \n\t" \ "lw $4, 24(%1) \n\t" \ "sw $4, 20($29) \n\t" \ "lw $4, 28(%1) \n\t" \ "sw $4, 24($29) \n\t" \ "lw $4, 32(%1) \n\t" \ "sw $4, 28($29) \n\t" \ "lw $4, 4(%1) \n\t" \ "lw $5, 8(%1) \n\t" \ "lw $6, 12(%1) \n\t" \ "lw $7, 16(%1) \n\t" \ "lw $25, 0(%1) \n\t" /* target->t9 */ \ VALGRIND_CALL_NOREDIR_T9 \ "addu $29, $29, 40 \n\t" \ "lw $28, 0($29) \n\t" \ "lw $31, 4($29) \n\t" \ "addu $29, $29, 8 \n\t" \ "move %0, $2\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[10]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ _argvec[9] = (unsigned long)(arg9); \ __asm__ volatile( \ "subu $29, $29, 8 \n\t" \ "sw $28, 0($29) \n\t" \ "sw $31, 4($29) \n\t" \ "lw $4, 20(%1) \n\t" \ "subu $29, $29, 40\n\t" \ "sw $4, 16($29) \n\t" \ "lw $4, 24(%1) \n\t" \ "sw $4, 20($29) \n\t" \ "lw $4, 28(%1) \n\t" \ "sw $4, 24($29) \n\t" \ "lw $4, 32(%1) \n\t" \ "sw $4, 28($29) \n\t" \ "lw $4, 36(%1) \n\t" \ "sw $4, 32($29) \n\t" \ "lw $4, 4(%1) \n\t" \ "lw $5, 8(%1) \n\t" \ "lw $6, 12(%1) \n\t" \ "lw $7, 16(%1) \n\t" \ "lw $25, 0(%1) \n\t" /* target->t9 */ \ VALGRIND_CALL_NOREDIR_T9 \ "addu $29, $29, 40 \n\t" \ "lw $28, 0($29) \n\t" \ "lw $31, 4($29) \n\t" \ "addu $29, $29, 8 \n\t" \ "move %0, $2\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9,arg10) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[11]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ _argvec[9] = (unsigned long)(arg9); \ _argvec[10] = (unsigned long)(arg10); \ __asm__ volatile( \ "subu $29, $29, 8 \n\t" \ "sw $28, 0($29) \n\t" \ "sw $31, 4($29) \n\t" \ "lw $4, 20(%1) \n\t" \ "subu $29, $29, 48\n\t" \ "sw $4, 16($29) \n\t" \ "lw $4, 24(%1) \n\t" \ "sw $4, 20($29) \n\t" \ "lw $4, 28(%1) \n\t" \ "sw $4, 24($29) \n\t" \ "lw $4, 32(%1) \n\t" \ "sw $4, 28($29) \n\t" \ "lw $4, 36(%1) \n\t" \ "sw $4, 32($29) \n\t" \ "lw $4, 40(%1) \n\t" \ "sw $4, 36($29) \n\t" \ "lw $4, 4(%1) \n\t" \ "lw $5, 8(%1) \n\t" \ "lw $6, 12(%1) \n\t" \ "lw $7, 16(%1) \n\t" \ "lw $25, 0(%1) \n\t" /* target->t9 */ \ VALGRIND_CALL_NOREDIR_T9 \ "addu $29, $29, 48 \n\t" \ "lw $28, 0($29) \n\t" \ "lw $31, 4($29) \n\t" \ "addu $29, $29, 8 \n\t" \ "move %0, $2\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5, \ arg6,arg7,arg8,arg9,arg10, \ arg11) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[12]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ _argvec[9] = (unsigned long)(arg9); \ _argvec[10] = (unsigned long)(arg10); \ _argvec[11] = (unsigned long)(arg11); \ __asm__ volatile( \ "subu $29, $29, 8 \n\t" \ "sw $28, 0($29) \n\t" \ "sw $31, 4($29) \n\t" \ "lw $4, 20(%1) \n\t" \ "subu $29, $29, 48\n\t" \ "sw $4, 16($29) \n\t" \ "lw $4, 24(%1) \n\t" \ "sw $4, 20($29) \n\t" \ "lw $4, 28(%1) \n\t" \ "sw $4, 24($29) \n\t" \ "lw $4, 32(%1) \n\t" \ "sw $4, 28($29) \n\t" \ "lw $4, 36(%1) \n\t" \ "sw $4, 32($29) \n\t" \ "lw $4, 40(%1) \n\t" \ "sw $4, 36($29) \n\t" \ "lw $4, 44(%1) \n\t" \ "sw $4, 40($29) \n\t" \ "lw $4, 4(%1) \n\t" \ "lw $5, 8(%1) \n\t" \ "lw $6, 12(%1) \n\t" \ "lw $7, 16(%1) \n\t" \ "lw $25, 0(%1) \n\t" /* target->t9 */ \ VALGRIND_CALL_NOREDIR_T9 \ "addu $29, $29, 48 \n\t" \ "lw $28, 0($29) \n\t" \ "lw $31, 4($29) \n\t" \ "addu $29, $29, 8 \n\t" \ "move %0, $2\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5, \ arg6,arg7,arg8,arg9,arg10, \ arg11,arg12) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[13]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ _argvec[9] = (unsigned long)(arg9); \ _argvec[10] = (unsigned long)(arg10); \ _argvec[11] = (unsigned long)(arg11); \ _argvec[12] = (unsigned long)(arg12); \ __asm__ volatile( \ "subu $29, $29, 8 \n\t" \ "sw $28, 0($29) \n\t" \ "sw $31, 4($29) \n\t" \ "lw $4, 20(%1) \n\t" \ "subu $29, $29, 56\n\t" \ "sw $4, 16($29) \n\t" \ "lw $4, 24(%1) \n\t" \ "sw $4, 20($29) \n\t" \ "lw $4, 28(%1) \n\t" \ "sw $4, 24($29) \n\t" \ "lw $4, 32(%1) \n\t" \ "sw $4, 28($29) \n\t" \ "lw $4, 36(%1) \n\t" \ "sw $4, 32($29) \n\t" \ "lw $4, 40(%1) \n\t" \ "sw $4, 36($29) \n\t" \ "lw $4, 44(%1) \n\t" \ "sw $4, 40($29) \n\t" \ "lw $4, 48(%1) \n\t" \ "sw $4, 44($29) \n\t" \ "lw $4, 4(%1) \n\t" \ "lw $5, 8(%1) \n\t" \ "lw $6, 12(%1) \n\t" \ "lw $7, 16(%1) \n\t" \ "lw $25, 0(%1) \n\t" /* target->t9 */ \ VALGRIND_CALL_NOREDIR_T9 \ "addu $29, $29, 56 \n\t" \ "lw $28, 0($29) \n\t" \ "lw $31, 4($29) \n\t" \ "addu $29, $29, 8 \n\t" \ "move %0, $2\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #endif /* PLAT_mips32_linux */ /* ------------------------- nanomips-linux -------------------- */ #if defined(PLAT_nanomips_linux) /* These regs are trashed by the hidden call. */ #define __CALLER_SAVED_REGS "$t4", "$t5", "$a0", "$a1", "$a2", \ "$a3", "$a4", "$a5", "$a6", "$a7", "$t0", "$t1", "$t2", "$t3", \ "$t8","$t9", "$at" /* These CALL_FN_ macros assume that on mips-linux, sizeof(unsigned long) == 4. */ #define CALL_FN_W_v(lval, orig) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[1]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ __asm__ volatile( \ "lw $t9, 0(%1)\n\t" \ VALGRIND_CALL_NOREDIR_T9 \ "move %0, $a0\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_W(lval, orig, arg1) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[2]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ __asm__ volatile( \ "lw $t9, 0(%1)\n\t" \ "lw $a0, 4(%1)\n\t" \ VALGRIND_CALL_NOREDIR_T9 \ "move %0, $a0\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WW(lval, orig, arg1,arg2) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ __asm__ volatile( \ "lw $t9, 0(%1)\n\t" \ "lw $a0, 4(%1)\n\t" \ "lw $a1, 8(%1)\n\t" \ VALGRIND_CALL_NOREDIR_T9 \ "move %0, $a0\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[4]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ __asm__ volatile( \ "lw $t9, 0(%1)\n\t" \ "lw $a0, 4(%1)\n\t" \ "lw $a1, 8(%1)\n\t" \ "lw $a2,12(%1)\n\t" \ VALGRIND_CALL_NOREDIR_T9 \ "move %0, $a0\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[5]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ __asm__ volatile( \ "lw $t9, 0(%1)\n\t" \ "lw $a0, 4(%1)\n\t" \ "lw $a1, 8(%1)\n\t" \ "lw $a2,12(%1)\n\t" \ "lw $a3,16(%1)\n\t" \ VALGRIND_CALL_NOREDIR_T9 \ "move %0, $a0\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[6]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ __asm__ volatile( \ "lw $t9, 0(%1)\n\t" \ "lw $a0, 4(%1)\n\t" \ "lw $a1, 8(%1)\n\t" \ "lw $a2,12(%1)\n\t" \ "lw $a3,16(%1)\n\t" \ "lw $a4,20(%1)\n\t" \ VALGRIND_CALL_NOREDIR_T9 \ "move %0, $a0\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[7]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ __asm__ volatile( \ "lw $t9, 0(%1)\n\t" \ "lw $a0, 4(%1)\n\t" \ "lw $a1, 8(%1)\n\t" \ "lw $a2,12(%1)\n\t" \ "lw $a3,16(%1)\n\t" \ "lw $a4,20(%1)\n\t" \ "lw $a5,24(%1)\n\t" \ VALGRIND_CALL_NOREDIR_T9 \ "move %0, $a0\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[8]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ __asm__ volatile( \ "lw $t9, 0(%1)\n\t" \ "lw $a0, 4(%1)\n\t" \ "lw $a1, 8(%1)\n\t" \ "lw $a2,12(%1)\n\t" \ "lw $a3,16(%1)\n\t" \ "lw $a4,20(%1)\n\t" \ "lw $a5,24(%1)\n\t" \ "lw $a6,28(%1)\n\t" \ VALGRIND_CALL_NOREDIR_T9 \ "move %0, $a0\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[9]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ __asm__ volatile( \ "lw $t9, 0(%1)\n\t" \ "lw $a0, 4(%1)\n\t" \ "lw $a1, 8(%1)\n\t" \ "lw $a2,12(%1)\n\t" \ "lw $a3,16(%1)\n\t" \ "lw $a4,20(%1)\n\t" \ "lw $a5,24(%1)\n\t" \ "lw $a6,28(%1)\n\t" \ "lw $a7,32(%1)\n\t" \ VALGRIND_CALL_NOREDIR_T9 \ "move %0, $a0\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[10]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ _argvec[9] = (unsigned long)(arg9); \ __asm__ volatile( \ "addiu $sp, $sp, -16 \n\t" \ "lw $t9,36(%1) \n\t" \ "sw $t9, 0($sp) \n\t" \ "lw $t9, 0(%1) \n\t" \ "lw $a0, 4(%1) \n\t" \ "lw $a1, 8(%1) \n\t" \ "lw $a2,12(%1) \n\t" \ "lw $a3,16(%1) \n\t" \ "lw $a4,20(%1) \n\t" \ "lw $a5,24(%1) \n\t" \ "lw $a6,28(%1) \n\t" \ "lw $a7,32(%1) \n\t" \ VALGRIND_CALL_NOREDIR_T9 \ "move %0, $a0 \n\t" \ "addiu $sp, $sp, 16 \n\t" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9,arg10) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[11]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ _argvec[9] = (unsigned long)(arg9); \ _argvec[10] = (unsigned long)(arg10); \ __asm__ volatile( \ "addiu $sp, $sp, -16 \n\t" \ "lw $t9,36(%1) \n\t" \ "sw $t9, 0($sp) \n\t" \ "lw $t9,40(%1) \n\t" \ "sw $t9, 4($sp) \n\t" \ "lw $t9, 0(%1) \n\t" \ "lw $a0, 4(%1) \n\t" \ "lw $a1, 8(%1) \n\t" \ "lw $a2,12(%1) \n\t" \ "lw $a3,16(%1) \n\t" \ "lw $a4,20(%1) \n\t" \ "lw $a5,24(%1) \n\t" \ "lw $a6,28(%1) \n\t" \ "lw $a7,32(%1) \n\t" \ VALGRIND_CALL_NOREDIR_T9 \ "move %0, $a0 \n\t" \ "addiu $sp, $sp, 16 \n\t" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5, \ arg6,arg7,arg8,arg9,arg10, \ arg11) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[12]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ _argvec[9] = (unsigned long)(arg9); \ _argvec[10] = (unsigned long)(arg10); \ _argvec[11] = (unsigned long)(arg11); \ __asm__ volatile( \ "addiu $sp, $sp, -16 \n\t" \ "lw $t9,36(%1) \n\t" \ "sw $t9, 0($sp) \n\t" \ "lw $t9,40(%1) \n\t" \ "sw $t9, 4($sp) \n\t" \ "lw $t9,44(%1) \n\t" \ "sw $t9, 8($sp) \n\t" \ "lw $t9, 0(%1) \n\t" \ "lw $a0, 4(%1) \n\t" \ "lw $a1, 8(%1) \n\t" \ "lw $a2,12(%1) \n\t" \ "lw $a3,16(%1) \n\t" \ "lw $a4,20(%1) \n\t" \ "lw $a5,24(%1) \n\t" \ "lw $a6,28(%1) \n\t" \ "lw $a7,32(%1) \n\t" \ VALGRIND_CALL_NOREDIR_T9 \ "move %0, $a0 \n\t" \ "addiu $sp, $sp, 16 \n\t" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5, \ arg6,arg7,arg8,arg9,arg10, \ arg11,arg12) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[13]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ _argvec[9] = (unsigned long)(arg9); \ _argvec[10] = (unsigned long)(arg10); \ _argvec[11] = (unsigned long)(arg11); \ _argvec[12] = (unsigned long)(arg12); \ __asm__ volatile( \ "addiu $sp, $sp, -16 \n\t" \ "lw $t9,36(%1) \n\t" \ "sw $t9, 0($sp) \n\t" \ "lw $t9,40(%1) \n\t" \ "sw $t9, 4($sp) \n\t" \ "lw $t9,44(%1) \n\t" \ "sw $t9, 8($sp) \n\t" \ "lw $t9,48(%1) \n\t" \ "sw $t9,12($sp) \n\t" \ "lw $t9, 0(%1) \n\t" \ "lw $a0, 4(%1) \n\t" \ "lw $a1, 8(%1) \n\t" \ "lw $a2,12(%1) \n\t" \ "lw $a3,16(%1) \n\t" \ "lw $a4,20(%1) \n\t" \ "lw $a5,24(%1) \n\t" \ "lw $a6,28(%1) \n\t" \ "lw $a7,32(%1) \n\t" \ VALGRIND_CALL_NOREDIR_T9 \ "move %0, $a0 \n\t" \ "addiu $sp, $sp, 16 \n\t" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #endif /* PLAT_nanomips_linux */ /* ------------------------- mips64-linux ------------------------- */ #if defined(PLAT_mips64_linux) /* These regs are trashed by the hidden call. */ #define __CALLER_SAVED_REGS "$2", "$3", "$4", "$5", "$6", \ "$7", "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15", "$24", \ "$25", "$31" /* These CALL_FN_ macros assume that on mips64-linux, sizeof(long long) == 8. */ #define MIPS64_LONG2REG_CAST(x) ((long long)(long)x) #define CALL_FN_W_v(lval, orig) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long long _argvec[1]; \ volatile unsigned long long _res; \ _argvec[0] = MIPS64_LONG2REG_CAST(_orig.nraddr); \ __asm__ volatile( \ "ld $25, 0(%1)\n\t" /* target->t9 */ \ VALGRIND_CALL_NOREDIR_T9 \ "move %0, $2\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) (long)_res; \ } while (0) #define CALL_FN_W_W(lval, orig, arg1) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long long _argvec[2]; \ volatile unsigned long long _res; \ _argvec[0] = MIPS64_LONG2REG_CAST(_orig.nraddr); \ _argvec[1] = MIPS64_LONG2REG_CAST(arg1); \ __asm__ volatile( \ "ld $4, 8(%1)\n\t" /* arg1*/ \ "ld $25, 0(%1)\n\t" /* target->t9 */ \ VALGRIND_CALL_NOREDIR_T9 \ "move %0, $2\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) (long)_res; \ } while (0) #define CALL_FN_W_WW(lval, orig, arg1,arg2) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long long _argvec[3]; \ volatile unsigned long long _res; \ _argvec[0] = _orig.nraddr; \ _argvec[1] = MIPS64_LONG2REG_CAST(arg1); \ _argvec[2] = MIPS64_LONG2REG_CAST(arg2); \ __asm__ volatile( \ "ld $4, 8(%1)\n\t" \ "ld $5, 16(%1)\n\t" \ "ld $25, 0(%1)\n\t" /* target->t9 */ \ VALGRIND_CALL_NOREDIR_T9 \ "move %0, $2\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) (long)_res; \ } while (0) #define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long long _argvec[4]; \ volatile unsigned long long _res; \ _argvec[0] = _orig.nraddr; \ _argvec[1] = MIPS64_LONG2REG_CAST(arg1); \ _argvec[2] = MIPS64_LONG2REG_CAST(arg2); \ _argvec[3] = MIPS64_LONG2REG_CAST(arg3); \ __asm__ volatile( \ "ld $4, 8(%1)\n\t" \ "ld $5, 16(%1)\n\t" \ "ld $6, 24(%1)\n\t" \ "ld $25, 0(%1)\n\t" /* target->t9 */ \ VALGRIND_CALL_NOREDIR_T9 \ "move %0, $2\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) (long)_res; \ } while (0) #define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long long _argvec[5]; \ volatile unsigned long long _res; \ _argvec[0] = MIPS64_LONG2REG_CAST(_orig.nraddr); \ _argvec[1] = MIPS64_LONG2REG_CAST(arg1); \ _argvec[2] = MIPS64_LONG2REG_CAST(arg2); \ _argvec[3] = MIPS64_LONG2REG_CAST(arg3); \ _argvec[4] = MIPS64_LONG2REG_CAST(arg4); \ __asm__ volatile( \ "ld $4, 8(%1)\n\t" \ "ld $5, 16(%1)\n\t" \ "ld $6, 24(%1)\n\t" \ "ld $7, 32(%1)\n\t" \ "ld $25, 0(%1)\n\t" /* target->t9 */ \ VALGRIND_CALL_NOREDIR_T9 \ "move %0, $2\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) (long)_res; \ } while (0) #define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long long _argvec[6]; \ volatile unsigned long long _res; \ _argvec[0] = MIPS64_LONG2REG_CAST(_orig.nraddr); \ _argvec[1] = MIPS64_LONG2REG_CAST(arg1); \ _argvec[2] = MIPS64_LONG2REG_CAST(arg2); \ _argvec[3] = MIPS64_LONG2REG_CAST(arg3); \ _argvec[4] = MIPS64_LONG2REG_CAST(arg4); \ _argvec[5] = MIPS64_LONG2REG_CAST(arg5); \ __asm__ volatile( \ "ld $4, 8(%1)\n\t" \ "ld $5, 16(%1)\n\t" \ "ld $6, 24(%1)\n\t" \ "ld $7, 32(%1)\n\t" \ "ld $8, 40(%1)\n\t" \ "ld $25, 0(%1)\n\t" /* target->t9 */ \ VALGRIND_CALL_NOREDIR_T9 \ "move %0, $2\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) (long)_res; \ } while (0) #define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long long _argvec[7]; \ volatile unsigned long long _res; \ _argvec[0] = MIPS64_LONG2REG_CAST(_orig.nraddr); \ _argvec[1] = MIPS64_LONG2REG_CAST(arg1); \ _argvec[2] = MIPS64_LONG2REG_CAST(arg2); \ _argvec[3] = MIPS64_LONG2REG_CAST(arg3); \ _argvec[4] = MIPS64_LONG2REG_CAST(arg4); \ _argvec[5] = MIPS64_LONG2REG_CAST(arg5); \ _argvec[6] = MIPS64_LONG2REG_CAST(arg6); \ __asm__ volatile( \ "ld $4, 8(%1)\n\t" \ "ld $5, 16(%1)\n\t" \ "ld $6, 24(%1)\n\t" \ "ld $7, 32(%1)\n\t" \ "ld $8, 40(%1)\n\t" \ "ld $9, 48(%1)\n\t" \ "ld $25, 0(%1)\n\t" /* target->t9 */ \ VALGRIND_CALL_NOREDIR_T9 \ "move %0, $2\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) (long)_res; \ } while (0) #define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long long _argvec[8]; \ volatile unsigned long long _res; \ _argvec[0] = MIPS64_LONG2REG_CAST(_orig.nraddr); \ _argvec[1] = MIPS64_LONG2REG_CAST(arg1); \ _argvec[2] = MIPS64_LONG2REG_CAST(arg2); \ _argvec[3] = MIPS64_LONG2REG_CAST(arg3); \ _argvec[4] = MIPS64_LONG2REG_CAST(arg4); \ _argvec[5] = MIPS64_LONG2REG_CAST(arg5); \ _argvec[6] = MIPS64_LONG2REG_CAST(arg6); \ _argvec[7] = MIPS64_LONG2REG_CAST(arg7); \ __asm__ volatile( \ "ld $4, 8(%1)\n\t" \ "ld $5, 16(%1)\n\t" \ "ld $6, 24(%1)\n\t" \ "ld $7, 32(%1)\n\t" \ "ld $8, 40(%1)\n\t" \ "ld $9, 48(%1)\n\t" \ "ld $10, 56(%1)\n\t" \ "ld $25, 0(%1) \n\t" /* target->t9 */ \ VALGRIND_CALL_NOREDIR_T9 \ "move %0, $2\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) (long)_res; \ } while (0) #define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long long _argvec[9]; \ volatile unsigned long long _res; \ _argvec[0] = MIPS64_LONG2REG_CAST(_orig.nraddr); \ _argvec[1] = MIPS64_LONG2REG_CAST(arg1); \ _argvec[2] = MIPS64_LONG2REG_CAST(arg2); \ _argvec[3] = MIPS64_LONG2REG_CAST(arg3); \ _argvec[4] = MIPS64_LONG2REG_CAST(arg4); \ _argvec[5] = MIPS64_LONG2REG_CAST(arg5); \ _argvec[6] = MIPS64_LONG2REG_CAST(arg6); \ _argvec[7] = MIPS64_LONG2REG_CAST(arg7); \ _argvec[8] = MIPS64_LONG2REG_CAST(arg8); \ __asm__ volatile( \ "ld $4, 8(%1)\n\t" \ "ld $5, 16(%1)\n\t" \ "ld $6, 24(%1)\n\t" \ "ld $7, 32(%1)\n\t" \ "ld $8, 40(%1)\n\t" \ "ld $9, 48(%1)\n\t" \ "ld $10, 56(%1)\n\t" \ "ld $11, 64(%1)\n\t" \ "ld $25, 0(%1) \n\t" /* target->t9 */ \ VALGRIND_CALL_NOREDIR_T9 \ "move %0, $2\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) (long)_res; \ } while (0) #define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long long _argvec[10]; \ volatile unsigned long long _res; \ _argvec[0] = MIPS64_LONG2REG_CAST(_orig.nraddr); \ _argvec[1] = MIPS64_LONG2REG_CAST(arg1); \ _argvec[2] = MIPS64_LONG2REG_CAST(arg2); \ _argvec[3] = MIPS64_LONG2REG_CAST(arg3); \ _argvec[4] = MIPS64_LONG2REG_CAST(arg4); \ _argvec[5] = MIPS64_LONG2REG_CAST(arg5); \ _argvec[6] = MIPS64_LONG2REG_CAST(arg6); \ _argvec[7] = MIPS64_LONG2REG_CAST(arg7); \ _argvec[8] = MIPS64_LONG2REG_CAST(arg8); \ _argvec[9] = MIPS64_LONG2REG_CAST(arg9); \ __asm__ volatile( \ "dsubu $29, $29, 8\n\t" \ "ld $4, 72(%1)\n\t" \ "sd $4, 0($29)\n\t" \ "ld $4, 8(%1)\n\t" \ "ld $5, 16(%1)\n\t" \ "ld $6, 24(%1)\n\t" \ "ld $7, 32(%1)\n\t" \ "ld $8, 40(%1)\n\t" \ "ld $9, 48(%1)\n\t" \ "ld $10, 56(%1)\n\t" \ "ld $11, 64(%1)\n\t" \ "ld $25, 0(%1)\n\t" /* target->t9 */ \ VALGRIND_CALL_NOREDIR_T9 \ "daddu $29, $29, 8\n\t" \ "move %0, $2\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) (long)_res; \ } while (0) #define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9,arg10) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long long _argvec[11]; \ volatile unsigned long long _res; \ _argvec[0] = MIPS64_LONG2REG_CAST(_orig.nraddr); \ _argvec[1] = MIPS64_LONG2REG_CAST(arg1); \ _argvec[2] = MIPS64_LONG2REG_CAST(arg2); \ _argvec[3] = MIPS64_LONG2REG_CAST(arg3); \ _argvec[4] = MIPS64_LONG2REG_CAST(arg4); \ _argvec[5] = MIPS64_LONG2REG_CAST(arg5); \ _argvec[6] = MIPS64_LONG2REG_CAST(arg6); \ _argvec[7] = MIPS64_LONG2REG_CAST(arg7); \ _argvec[8] = MIPS64_LONG2REG_CAST(arg8); \ _argvec[9] = MIPS64_LONG2REG_CAST(arg9); \ _argvec[10] = MIPS64_LONG2REG_CAST(arg10); \ __asm__ volatile( \ "dsubu $29, $29, 16\n\t" \ "ld $4, 72(%1)\n\t" \ "sd $4, 0($29)\n\t" \ "ld $4, 80(%1)\n\t" \ "sd $4, 8($29)\n\t" \ "ld $4, 8(%1)\n\t" \ "ld $5, 16(%1)\n\t" \ "ld $6, 24(%1)\n\t" \ "ld $7, 32(%1)\n\t" \ "ld $8, 40(%1)\n\t" \ "ld $9, 48(%1)\n\t" \ "ld $10, 56(%1)\n\t" \ "ld $11, 64(%1)\n\t" \ "ld $25, 0(%1)\n\t" /* target->t9 */ \ VALGRIND_CALL_NOREDIR_T9 \ "daddu $29, $29, 16\n\t" \ "move %0, $2\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) (long)_res; \ } while (0) #define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5, \ arg6,arg7,arg8,arg9,arg10, \ arg11) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long long _argvec[12]; \ volatile unsigned long long _res; \ _argvec[0] = MIPS64_LONG2REG_CAST(_orig.nraddr); \ _argvec[1] = MIPS64_LONG2REG_CAST(arg1); \ _argvec[2] = MIPS64_LONG2REG_CAST(arg2); \ _argvec[3] = MIPS64_LONG2REG_CAST(arg3); \ _argvec[4] = MIPS64_LONG2REG_CAST(arg4); \ _argvec[5] = MIPS64_LONG2REG_CAST(arg5); \ _argvec[6] = MIPS64_LONG2REG_CAST(arg6); \ _argvec[7] = MIPS64_LONG2REG_CAST(arg7); \ _argvec[8] = MIPS64_LONG2REG_CAST(arg8); \ _argvec[9] = MIPS64_LONG2REG_CAST(arg9); \ _argvec[10] = MIPS64_LONG2REG_CAST(arg10); \ _argvec[11] = MIPS64_LONG2REG_CAST(arg11); \ __asm__ volatile( \ "dsubu $29, $29, 24\n\t" \ "ld $4, 72(%1)\n\t" \ "sd $4, 0($29)\n\t" \ "ld $4, 80(%1)\n\t" \ "sd $4, 8($29)\n\t" \ "ld $4, 88(%1)\n\t" \ "sd $4, 16($29)\n\t" \ "ld $4, 8(%1)\n\t" \ "ld $5, 16(%1)\n\t" \ "ld $6, 24(%1)\n\t" \ "ld $7, 32(%1)\n\t" \ "ld $8, 40(%1)\n\t" \ "ld $9, 48(%1)\n\t" \ "ld $10, 56(%1)\n\t" \ "ld $11, 64(%1)\n\t" \ "ld $25, 0(%1)\n\t" /* target->t9 */ \ VALGRIND_CALL_NOREDIR_T9 \ "daddu $29, $29, 24\n\t" \ "move %0, $2\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) (long)_res; \ } while (0) #define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5, \ arg6,arg7,arg8,arg9,arg10, \ arg11,arg12) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long long _argvec[13]; \ volatile unsigned long long _res; \ _argvec[0] = MIPS64_LONG2REG_CAST(_orig.nraddr); \ _argvec[1] = MIPS64_LONG2REG_CAST(arg1); \ _argvec[2] = MIPS64_LONG2REG_CAST(arg2); \ _argvec[3] = MIPS64_LONG2REG_CAST(arg3); \ _argvec[4] = MIPS64_LONG2REG_CAST(arg4); \ _argvec[5] = MIPS64_LONG2REG_CAST(arg5); \ _argvec[6] = MIPS64_LONG2REG_CAST(arg6); \ _argvec[7] = MIPS64_LONG2REG_CAST(arg7); \ _argvec[8] = MIPS64_LONG2REG_CAST(arg8); \ _argvec[9] = MIPS64_LONG2REG_CAST(arg9); \ _argvec[10] = MIPS64_LONG2REG_CAST(arg10); \ _argvec[11] = MIPS64_LONG2REG_CAST(arg11); \ _argvec[12] = MIPS64_LONG2REG_CAST(arg12); \ __asm__ volatile( \ "dsubu $29, $29, 32\n\t" \ "ld $4, 72(%1)\n\t" \ "sd $4, 0($29)\n\t" \ "ld $4, 80(%1)\n\t" \ "sd $4, 8($29)\n\t" \ "ld $4, 88(%1)\n\t" \ "sd $4, 16($29)\n\t" \ "ld $4, 96(%1)\n\t" \ "sd $4, 24($29)\n\t" \ "ld $4, 8(%1)\n\t" \ "ld $5, 16(%1)\n\t" \ "ld $6, 24(%1)\n\t" \ "ld $7, 32(%1)\n\t" \ "ld $8, 40(%1)\n\t" \ "ld $9, 48(%1)\n\t" \ "ld $10, 56(%1)\n\t" \ "ld $11, 64(%1)\n\t" \ "ld $25, 0(%1)\n\t" /* target->t9 */ \ VALGRIND_CALL_NOREDIR_T9 \ "daddu $29, $29, 32\n\t" \ "move %0, $2\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) (long)_res; \ } while (0) #endif /* PLAT_mips64_linux */ /* ------------------------------------------------------------------ */ /* ARCHITECTURE INDEPENDENT MACROS for CLIENT REQUESTS. */ /* */ /* ------------------------------------------------------------------ */ /* Some request codes. There are many more of these, but most are not exposed to end-user view. These are the public ones, all of the form 0x1000 + small_number. Core ones are in the range 0x00000000--0x0000ffff. The non-public ones start at 0x2000. */ /* These macros are used by tools -- they must be public, but don't embed them into other programs. */ #define VG_USERREQ_TOOL_BASE(a,b) \ ((unsigned int)(((a)&0xff) << 24 | ((b)&0xff) << 16)) #define VG_IS_TOOL_USERREQ(a, b, v) \ (VG_USERREQ_TOOL_BASE(a,b) == ((v) & 0xffff0000)) /* !! ABIWARNING !! ABIWARNING !! ABIWARNING !! ABIWARNING !! This enum comprises an ABI exported by Valgrind to programs which use client requests. DO NOT CHANGE THE NUMERIC VALUES OF THESE ENTRIES, NOR DELETE ANY -- add new ones at the end of the most relevant group. */ typedef enum { VG_USERREQ__RUNNING_ON_VALGRIND = 0x1001, VG_USERREQ__DISCARD_TRANSLATIONS = 0x1002, /* These allow any function to be called from the simulated CPU but run on the real CPU. Nb: the first arg passed to the function is always the ThreadId of the running thread! So CLIENT_CALL0 actually requires a 1 arg function, etc. */ VG_USERREQ__CLIENT_CALL0 = 0x1101, VG_USERREQ__CLIENT_CALL1 = 0x1102, VG_USERREQ__CLIENT_CALL2 = 0x1103, VG_USERREQ__CLIENT_CALL3 = 0x1104, /* Can be useful in regression testing suites -- eg. can send Valgrind's output to /dev/null and still count errors. */ VG_USERREQ__COUNT_ERRORS = 0x1201, /* Allows the client program and/or gdbserver to execute a monitor command. */ VG_USERREQ__GDB_MONITOR_COMMAND = 0x1202, /* Allows the client program to change a dynamic command line option. */ VG_USERREQ__CLO_CHANGE = 0x1203, /* These are useful and can be interpreted by any tool that tracks malloc() et al, by using vg_replace_malloc.c. */ VG_USERREQ__MALLOCLIKE_BLOCK = 0x1301, VG_USERREQ__RESIZEINPLACE_BLOCK = 0x130b, VG_USERREQ__FREELIKE_BLOCK = 0x1302, /* Memory pool support. */ VG_USERREQ__CREATE_MEMPOOL = 0x1303, VG_USERREQ__DESTROY_MEMPOOL = 0x1304, VG_USERREQ__MEMPOOL_ALLOC = 0x1305, VG_USERREQ__MEMPOOL_FREE = 0x1306, VG_USERREQ__MEMPOOL_TRIM = 0x1307, VG_USERREQ__MOVE_MEMPOOL = 0x1308, VG_USERREQ__MEMPOOL_CHANGE = 0x1309, VG_USERREQ__MEMPOOL_EXISTS = 0x130a, /* Allow printfs to valgrind log. */ /* The first two pass the va_list argument by value, which assumes it is the same size as or smaller than a UWord, which generally isn't the case. Hence are deprecated. The second two pass the vargs by reference and so are immune to this problem. */ /* both :: char* fmt, va_list vargs (DEPRECATED) */ VG_USERREQ__PRINTF = 0x1401, VG_USERREQ__PRINTF_BACKTRACE = 0x1402, /* both :: char* fmt, va_list* vargs */ VG_USERREQ__PRINTF_VALIST_BY_REF = 0x1403, VG_USERREQ__PRINTF_BACKTRACE_VALIST_BY_REF = 0x1404, /* Stack support. */ VG_USERREQ__STACK_REGISTER = 0x1501, VG_USERREQ__STACK_DEREGISTER = 0x1502, VG_USERREQ__STACK_CHANGE = 0x1503, /* Wine support */ VG_USERREQ__LOAD_PDB_DEBUGINFO = 0x1601, /* Querying of debug info. */ VG_USERREQ__MAP_IP_TO_SRCLOC = 0x1701, /* Disable/enable error reporting level. Takes a single Word arg which is the delta to this thread's error disablement indicator. Hence 1 disables or further disables errors, and -1 moves back towards enablement. Other values are not allowed. */ VG_USERREQ__CHANGE_ERR_DISABLEMENT = 0x1801, /* Some requests used for Valgrind internal, such as self-test or self-hosting. */ /* Initialise IR injection */ VG_USERREQ__VEX_INIT_FOR_IRI = 0x1901, /* Used by Inner Valgrind to inform Outer Valgrind where to find the list of inner guest threads */ VG_USERREQ__INNER_THREADS = 0x1902 } Vg_ClientRequest; #if !defined(__GNUC__) # define __extension__ /* */ #endif /* Returns the number of Valgrinds this code is running under. That is, 0 if running natively, 1 if running under Valgrind, 2 if running under Valgrind which is running under another Valgrind, etc. */ #define RUNNING_ON_VALGRIND \ (unsigned)VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* if not */, \ VG_USERREQ__RUNNING_ON_VALGRIND, \ 0, 0, 0, 0, 0) \ /* Discard translation of code in the range [_qzz_addr .. _qzz_addr + _qzz_len - 1]. Useful if you are debugging a JITter or some such, since it provides a way to make sure valgrind will retranslate the invalidated area. Returns no value. */ #define VALGRIND_DISCARD_TRANSLATIONS(_qzz_addr,_qzz_len) \ VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__DISCARD_TRANSLATIONS, \ _qzz_addr, _qzz_len, 0, 0, 0) #define VALGRIND_INNER_THREADS(_qzz_addr) \ VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__INNER_THREADS, \ _qzz_addr, 0, 0, 0, 0) /* These requests are for getting Valgrind itself to print something. Possibly with a backtrace. This is a really ugly hack. The return value is the number of characters printed, excluding the "**** " part at the start and the backtrace (if present). */ #if defined(__GNUC__) || defined(__INTEL_COMPILER) && !defined(_MSC_VER) /* Modern GCC will optimize the static routine out if unused, and unused attribute will shut down warnings about it. */ static int VALGRIND_PRINTF(const char *format, ...) __attribute__((format(__printf__, 1, 2), __unused__)); #endif static int #if defined(_MSC_VER) __inline #endif VALGRIND_PRINTF(const char *format, ...) { #if defined(NVALGRIND) (void)format; return 0; #else /* NVALGRIND */ #if defined(_MSC_VER) || defined(__MINGW64__) uintptr_t _qzz_res; #else unsigned long _qzz_res; #endif va_list vargs; va_start(vargs, format); #if defined(_MSC_VER) || defined(__MINGW64__) _qzz_res = VALGRIND_DO_CLIENT_REQUEST_EXPR(0, VG_USERREQ__PRINTF_VALIST_BY_REF, (uintptr_t)format, (uintptr_t)&vargs, 0, 0, 0); #else _qzz_res = VALGRIND_DO_CLIENT_REQUEST_EXPR(0, VG_USERREQ__PRINTF_VALIST_BY_REF, (unsigned long)format, (unsigned long)&vargs, 0, 0, 0); #endif va_end(vargs); return (int)_qzz_res; #endif /* NVALGRIND */ } #if defined(__GNUC__) || defined(__INTEL_COMPILER) && !defined(_MSC_VER) static int VALGRIND_PRINTF_BACKTRACE(const char *format, ...) __attribute__((format(__printf__, 1, 2), __unused__)); #endif static int #if defined(_MSC_VER) __inline #endif VALGRIND_PRINTF_BACKTRACE(const char *format, ...) { #if defined(NVALGRIND) (void)format; return 0; #else /* NVALGRIND */ #if defined(_MSC_VER) || defined(__MINGW64__) uintptr_t _qzz_res; #else unsigned long _qzz_res; #endif va_list vargs; va_start(vargs, format); #if defined(_MSC_VER) || defined(__MINGW64__) _qzz_res = VALGRIND_DO_CLIENT_REQUEST_EXPR(0, VG_USERREQ__PRINTF_BACKTRACE_VALIST_BY_REF, (uintptr_t)format, (uintptr_t)&vargs, 0, 0, 0); #else _qzz_res = VALGRIND_DO_CLIENT_REQUEST_EXPR(0, VG_USERREQ__PRINTF_BACKTRACE_VALIST_BY_REF, (unsigned long)format, (unsigned long)&vargs, 0, 0, 0); #endif va_end(vargs); return (int)_qzz_res; #endif /* NVALGRIND */ } /* These requests allow control to move from the simulated CPU to the real CPU, calling an arbitrary function. Note that the current ThreadId is inserted as the first argument. So this call: VALGRIND_NON_SIMD_CALL2(f, arg1, arg2) requires f to have this signature: Word f(Word tid, Word arg1, Word arg2) where "Word" is a word-sized type. Note that these client requests are not entirely reliable. For example, if you call a function with them that subsequently calls printf(), there's a high chance Valgrind will crash. Generally, your prospects of these working are made higher if the called function does not refer to any global variables, and does not refer to any libc or other functions (printf et al). Any kind of entanglement with libc or dynamic linking is likely to have a bad outcome, for tricky reasons which we've grappled with a lot in the past. */ #define VALGRIND_NON_SIMD_CALL0(_qyy_fn) \ VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* default return */, \ VG_USERREQ__CLIENT_CALL0, \ _qyy_fn, \ 0, 0, 0, 0) #define VALGRIND_NON_SIMD_CALL1(_qyy_fn, _qyy_arg1) \ VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* default return */, \ VG_USERREQ__CLIENT_CALL1, \ _qyy_fn, \ _qyy_arg1, 0, 0, 0) #define VALGRIND_NON_SIMD_CALL2(_qyy_fn, _qyy_arg1, _qyy_arg2) \ VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* default return */, \ VG_USERREQ__CLIENT_CALL2, \ _qyy_fn, \ _qyy_arg1, _qyy_arg2, 0, 0) #define VALGRIND_NON_SIMD_CALL3(_qyy_fn, _qyy_arg1, _qyy_arg2, _qyy_arg3) \ VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* default return */, \ VG_USERREQ__CLIENT_CALL3, \ _qyy_fn, \ _qyy_arg1, _qyy_arg2, \ _qyy_arg3, 0) /* Counts the number of errors that have been recorded by a tool. Nb: the tool must record the errors with VG_(maybe_record_error)() or VG_(unique_error)() for them to be counted. */ #define VALGRIND_COUNT_ERRORS \ (unsigned)VALGRIND_DO_CLIENT_REQUEST_EXPR( \ 0 /* default return */, \ VG_USERREQ__COUNT_ERRORS, \ 0, 0, 0, 0, 0) /* Several Valgrind tools (Memcheck, Massif, Helgrind, DRD) rely on knowing when heap blocks are allocated in order to give accurate results. This happens automatically for the standard allocator functions such as malloc(), calloc(), realloc(), memalign(), new, new[], free(), delete, delete[], etc. But if your program uses a custom allocator, this doesn't automatically happen, and Valgrind will not do as well. For example, if you allocate superblocks with mmap() and then allocates chunks of the superblocks, all Valgrind's observations will be at the mmap() level and it won't know that the chunks should be considered separate entities. In Memcheck's case, that means you probably won't get heap block overrun detection (because there won't be redzones marked as unaddressable) and you definitely won't get any leak detection. The following client requests allow a custom allocator to be annotated so that it can be handled accurately by Valgrind. VALGRIND_MALLOCLIKE_BLOCK marks a region of memory as having been allocated by a malloc()-like function. For Memcheck (an illustrative case), this does two things: - It records that the block has been allocated. This means any addresses within the block mentioned in error messages will be identified as belonging to the block. It also means that if the block isn't freed it will be detected by the leak checker. - It marks the block as being addressable and undefined (if 'is_zeroed' is not set), or addressable and defined (if 'is_zeroed' is set). This controls how accesses to the block by the program are handled. 'addr' is the start of the usable block (ie. after any redzone), 'sizeB' is its size. 'rzB' is the redzone size if the allocator can apply redzones -- these are blocks of padding at the start and end of each block. Adding redzones is recommended as it makes it much more likely Valgrind will spot block overruns. `is_zeroed' indicates if the memory is zeroed (or filled with another predictable value), as is the case for calloc(). VALGRIND_MALLOCLIKE_BLOCK should be put immediately after the point where a heap block -- that will be used by the client program -- is allocated. It's best to put it at the outermost level of the allocator if possible; for example, if you have a function my_alloc() which calls internal_alloc(), and the client request is put inside internal_alloc(), stack traces relating to the heap block will contain entries for both my_alloc() and internal_alloc(), which is probably not what you want. For Memcheck users: if you use VALGRIND_MALLOCLIKE_BLOCK to carve out custom blocks from within a heap block, B, that has been allocated with malloc/calloc/new/etc, then block B will be *ignored* during leak-checking -- the custom blocks will take precedence. VALGRIND_FREELIKE_BLOCK is the partner to VALGRIND_MALLOCLIKE_BLOCK. For Memcheck, it does two things: - It records that the block has been deallocated. This assumes that the block was annotated as having been allocated via VALGRIND_MALLOCLIKE_BLOCK. Otherwise, an error will be issued. - It marks the block as being unaddressable. VALGRIND_FREELIKE_BLOCK should be put immediately after the point where a heap block is deallocated. VALGRIND_RESIZEINPLACE_BLOCK informs a tool about reallocation. For Memcheck, it does four things: - It records that the size of a block has been changed. This assumes that the block was annotated as having been allocated via VALGRIND_MALLOCLIKE_BLOCK. Otherwise, an error will be issued. - If the block shrunk, it marks the freed memory as being unaddressable. - If the block grew, it marks the new area as undefined and defines a red zone past the end of the new block. - The V-bits of the overlap between the old and the new block are preserved. VALGRIND_RESIZEINPLACE_BLOCK should be put after allocation of the new block and before deallocation of the old block. In many cases, these three client requests will not be enough to get your allocator working well with Memcheck. More specifically, if your allocator writes to freed blocks in any way then a VALGRIND_MAKE_MEM_UNDEFINED call will be necessary to mark the memory as addressable just before the zeroing occurs, otherwise you'll get a lot of invalid write errors. For example, you'll need to do this if your allocator recycles freed blocks, but it zeroes them before handing them back out (via VALGRIND_MALLOCLIKE_BLOCK). Alternatively, if your allocator reuses freed blocks for allocator-internal data structures, VALGRIND_MAKE_MEM_UNDEFINED calls will also be necessary. Really, what's happening is a blurring of the lines between the client program and the allocator... after VALGRIND_FREELIKE_BLOCK is called, the memory should be considered unaddressable to the client program, but the allocator knows more than the rest of the client program and so may be able to safely access it. Extra client requests are necessary for Valgrind to understand the distinction between the allocator and the rest of the program. Ignored if addr == 0. */ #define VALGRIND_MALLOCLIKE_BLOCK(addr, sizeB, rzB, is_zeroed) \ VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__MALLOCLIKE_BLOCK, \ addr, sizeB, rzB, is_zeroed, 0) /* See the comment for VALGRIND_MALLOCLIKE_BLOCK for details. Ignored if addr == 0. */ #define VALGRIND_RESIZEINPLACE_BLOCK(addr, oldSizeB, newSizeB, rzB) \ VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__RESIZEINPLACE_BLOCK, \ addr, oldSizeB, newSizeB, rzB, 0) /* See the comment for VALGRIND_MALLOCLIKE_BLOCK for details. Ignored if addr == 0. */ #define VALGRIND_FREELIKE_BLOCK(addr, rzB) \ VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__FREELIKE_BLOCK, \ addr, rzB, 0, 0, 0) /* Create a memory pool. */ #define VALGRIND_CREATE_MEMPOOL(pool, rzB, is_zeroed) \ VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__CREATE_MEMPOOL, \ pool, rzB, is_zeroed, 0, 0) /* Create a memory pool with some flags specifying extended behaviour. When flags is zero, the behaviour is identical to VALGRIND_CREATE_MEMPOOL. The flag VALGRIND_MEMPOOL_METAPOOL specifies that the pieces of memory associated with the pool using VALGRIND_MEMPOOL_ALLOC will be used by the application as superblocks to dole out MALLOC_LIKE blocks using VALGRIND_MALLOCLIKE_BLOCK. In other words, a meta pool is a "2 levels" pool : first level is the blocks described by VALGRIND_MEMPOOL_ALLOC. The second level blocks are described using VALGRIND_MALLOCLIKE_BLOCK. Note that the association between the pool and the second level blocks is implicit : second level blocks will be located inside first level blocks. It is necessary to use the VALGRIND_MEMPOOL_METAPOOL flag for such 2 levels pools, as otherwise valgrind will detect overlapping memory blocks, and will abort execution (e.g. during leak search). Such a meta pool can also be marked as an 'auto free' pool using the flag VALGRIND_MEMPOOL_AUTO_FREE, which must be OR-ed together with the VALGRIND_MEMPOOL_METAPOOL. For an 'auto free' pool, VALGRIND_MEMPOOL_FREE will automatically free the second level blocks that are contained inside the first level block freed with VALGRIND_MEMPOOL_FREE. In other words, calling VALGRIND_MEMPOOL_FREE will cause implicit calls to VALGRIND_FREELIKE_BLOCK for all the second level blocks included in the first level block. Note: it is an error to use the VALGRIND_MEMPOOL_AUTO_FREE flag without the VALGRIND_MEMPOOL_METAPOOL flag. */ #define VALGRIND_MEMPOOL_AUTO_FREE 1 #define VALGRIND_MEMPOOL_METAPOOL 2 #define VALGRIND_CREATE_MEMPOOL_EXT(pool, rzB, is_zeroed, flags) \ VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__CREATE_MEMPOOL, \ pool, rzB, is_zeroed, flags, 0) /* Destroy a memory pool. */ #define VALGRIND_DESTROY_MEMPOOL(pool) \ VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__DESTROY_MEMPOOL, \ pool, 0, 0, 0, 0) /* Associate a piece of memory with a memory pool. */ #define VALGRIND_MEMPOOL_ALLOC(pool, addr, size) \ VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__MEMPOOL_ALLOC, \ pool, addr, size, 0, 0) /* Disassociate a piece of memory from a memory pool. */ #define VALGRIND_MEMPOOL_FREE(pool, addr) \ VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__MEMPOOL_FREE, \ pool, addr, 0, 0, 0) /* Disassociate any pieces outside a particular range. */ #define VALGRIND_MEMPOOL_TRIM(pool, addr, size) \ VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__MEMPOOL_TRIM, \ pool, addr, size, 0, 0) /* Resize and/or move a piece associated with a memory pool. */ #define VALGRIND_MOVE_MEMPOOL(poolA, poolB) \ VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__MOVE_MEMPOOL, \ poolA, poolB, 0, 0, 0) /* Resize and/or move a piece associated with a memory pool. */ #define VALGRIND_MEMPOOL_CHANGE(pool, addrA, addrB, size) \ VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__MEMPOOL_CHANGE, \ pool, addrA, addrB, size, 0) /* Return 1 if a mempool exists, else 0. */ #define VALGRIND_MEMPOOL_EXISTS(pool) \ (unsigned)VALGRIND_DO_CLIENT_REQUEST_EXPR(0, \ VG_USERREQ__MEMPOOL_EXISTS, \ pool, 0, 0, 0, 0) /* Mark a piece of memory as being a stack. Returns a stack id. start is the lowest addressable stack byte, end is the highest addressable stack byte. */ #define VALGRIND_STACK_REGISTER(start, end) \ (unsigned)VALGRIND_DO_CLIENT_REQUEST_EXPR(0, \ VG_USERREQ__STACK_REGISTER, \ start, end, 0, 0, 0) /* Unmark the piece of memory associated with a stack id as being a stack. */ #define VALGRIND_STACK_DEREGISTER(id) \ VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__STACK_DEREGISTER, \ id, 0, 0, 0, 0) /* Change the start and end address of the stack id. start is the new lowest addressable stack byte, end is the new highest addressable stack byte. */ #define VALGRIND_STACK_CHANGE(id, start, end) \ VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__STACK_CHANGE, \ id, start, end, 0, 0) /* Load PDB debug info for Wine PE image_map. */ #define VALGRIND_LOAD_PDB_DEBUGINFO(fd, ptr, total_size, delta) \ VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__LOAD_PDB_DEBUGINFO, \ fd, ptr, total_size, delta, 0) /* Map a code address to a source file name and line number. buf64 must point to a 64-byte buffer in the caller's address space. The result will be dumped in there and is guaranteed to be zero terminated. If no info is found, the first byte is set to zero. */ #define VALGRIND_MAP_IP_TO_SRCLOC(addr, buf64) \ (unsigned)VALGRIND_DO_CLIENT_REQUEST_EXPR(0, \ VG_USERREQ__MAP_IP_TO_SRCLOC, \ addr, buf64, 0, 0, 0) /* Disable error reporting for this thread. Behaves in a stack like way, so you can safely call this multiple times provided that VALGRIND_ENABLE_ERROR_REPORTING is called the same number of times to re-enable reporting. The first call of this macro disables reporting. Subsequent calls have no effect except to increase the number of VALGRIND_ENABLE_ERROR_REPORTING calls needed to re-enable reporting. Child threads do not inherit this setting from their parents -- they are always created with reporting enabled. */ #define VALGRIND_DISABLE_ERROR_REPORTING \ VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__CHANGE_ERR_DISABLEMENT, \ 1, 0, 0, 0, 0) /* Re-enable error reporting, as per comments on VALGRIND_DISABLE_ERROR_REPORTING. */ #define VALGRIND_ENABLE_ERROR_REPORTING \ VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__CHANGE_ERR_DISABLEMENT, \ -1, 0, 0, 0, 0) /* Execute a monitor command from the client program. If a connection is opened with GDB, the output will be sent according to the output mode set for vgdb. If no connection is opened, output will go to the log output. Returns 1 if command not recognised, 0 otherwise. */ #define VALGRIND_MONITOR_COMMAND(command) \ VALGRIND_DO_CLIENT_REQUEST_EXPR(0, VG_USERREQ__GDB_MONITOR_COMMAND, \ command, 0, 0, 0, 0) /* Change the value of a dynamic command line option. Note that unknown or not dynamically changeable options will cause a warning message to be output. */ #define VALGRIND_CLO_CHANGE(option) \ VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__CLO_CHANGE, \ option, 0, 0, 0, 0) #undef PLAT_x86_darwin #undef PLAT_amd64_darwin #undef PLAT_x86_win32 #undef PLAT_amd64_win64 #undef PLAT_x86_linux #undef PLAT_amd64_linux #undef PLAT_ppc32_linux #undef PLAT_ppc64be_linux #undef PLAT_ppc64le_linux #undef PLAT_arm_linux #undef PLAT_s390x_linux #undef PLAT_mips32_linux #undef PLAT_mips64_linux #undef PLAT_nanomips_linux #undef PLAT_x86_solaris #undef PLAT_amd64_solaris #endif /* __VALGRIND_H */ librecast/test/zzz/000077500000000000000000000000001502456746400146575ustar00rootroot00000000000000librecast/test/zzz/0000-0062.test000077700000000000000000000000001502456746400205772../0000-0062.testustar00rootroot00000000000000librecast/test/zzz/0000-0217.test000077700000000000000000000000001502456746400206032../0000-0217.testustar00rootroot00000000000000librecast/test/zzz/README000066400000000000000000000002271502456746400155400ustar00rootroot00000000000000# zzz This groups contains tests that are slow, and so aren't part of test/all. They do need running for regression testing from time to time though.