1 // SPDX-License-Identifier: 0BSD 2 3 /////////////////////////////////////////////////////////////////////////////// 4 // 5 /// \file crc64.c 6 /// \brief CRC64 calculation 7 // 8 // Authors: Lasse Collin 9 // Ilya Kurdyukov 10 // 11 /////////////////////////////////////////////////////////////////////////////// 12 13 #include "check.h" 14 #include "crc_common.h" 15 16 #if defined(CRC_X86_CLMUL) 17 # define BUILDING_CRC_CLMUL 64 18 # include "crc_x86_clmul.h" 19 #endif 20 21 22 #ifdef CRC64_GENERIC 23 24 ///////////////////////////////// 25 // Generic slice-by-four CRC64 // 26 ///////////////////////////////// 27 28 #if defined(WORDS_BIGENDIAN) 29 # include "crc64_table_be.h" 30 #else 31 # include "crc64_table_le.h" 32 #endif 33 34 35 #ifdef HAVE_CRC_X86_ASM 36 extern uint64_t lzma_crc64_generic( 37 const uint8_t *buf, size_t size, uint64_t crc); 38 #else 39 40 #ifdef WORDS_BIGENDIAN 41 # define A1(x) ((x) >> 56) 42 #else 43 # define A1 A 44 #endif 45 46 47 // See the comments in crc32_fast.c. They aren't duplicated here. 48 static uint64_t 49 lzma_crc64_generic(const uint8_t *buf, size_t size, uint64_t crc) 50 { 51 crc = ~crc; 52 53 #ifdef WORDS_BIGENDIAN 54 crc = byteswap64(crc); 55 #endif 56 57 if (size > 4) { 58 while ((uintptr_t)(buf) & 3) { 59 crc = lzma_crc64_table[0][*buf++ ^ A1(crc)] ^ S8(crc); 60 --size; 61 } 62 63 const uint8_t *const limit = buf + (size & ~(size_t)(3)); 64 size &= (size_t)(3); 65 66 while (buf < limit) { 67 #ifdef WORDS_BIGENDIAN 68 const uint32_t tmp = (uint32_t)(crc >> 32) 69 ^ aligned_read32ne(buf); 70 #else 71 const uint32_t tmp = (uint32_t)crc 72 ^ aligned_read32ne(buf); 73 #endif 74 buf += 4; 75 76 crc = lzma_crc64_table[3][A(tmp)] 77 ^ lzma_crc64_table[2][B(tmp)] 78 ^ S32(crc) 79 ^ lzma_crc64_table[1][C(tmp)] 80 ^ lzma_crc64_table[0][D(tmp)]; 81 } 82 } 83 84 while (size-- != 0) 85 crc = lzma_crc64_table[0][*buf++ ^ A1(crc)] ^ S8(crc); 86 87 #ifdef WORDS_BIGENDIAN 88 crc = byteswap64(crc); 89 #endif 90 91 return ~crc; 92 } 93 #endif // HAVE_CRC_X86_ASM 94 #endif // CRC64_GENERIC 95 96 97 #if defined(CRC64_GENERIC) && defined(CRC64_ARCH_OPTIMIZED) 98 99 ////////////////////////// 100 // Function dispatching // 101 ////////////////////////// 102 103 // If both the generic and arch-optimized implementations are usable, then 104 // the function that is used is selected at runtime. See crc32_fast.c. 105 106 typedef uint64_t (*crc64_func_type)( 107 const uint8_t *buf, size_t size, uint64_t crc); 108 109 static crc64_func_type 110 crc64_resolve(void) 111 { 112 return is_arch_extension_supported() 113 ? &crc64_arch_optimized : &lzma_crc64_generic; 114 } 115 116 #ifdef HAVE_FUNC_ATTRIBUTE_CONSTRUCTOR 117 # define CRC64_SET_FUNC_ATTR __attribute__((__constructor__)) 118 static crc64_func_type crc64_func; 119 #else 120 # define CRC64_SET_FUNC_ATTR 121 static uint64_t crc64_dispatch(const uint8_t *buf, size_t size, uint64_t crc); 122 static crc64_func_type crc64_func = &crc64_dispatch; 123 #endif 124 125 126 CRC64_SET_FUNC_ATTR 127 static void 128 crc64_set_func(void) 129 { 130 crc64_func = crc64_resolve(); 131 return; 132 } 133 134 135 #ifndef HAVE_FUNC_ATTRIBUTE_CONSTRUCTOR 136 static uint64_t 137 crc64_dispatch(const uint8_t *buf, size_t size, uint64_t crc) 138 { 139 crc64_set_func(); 140 return crc64_func(buf, size, crc); 141 } 142 #endif 143 #endif 144 145 146 extern LZMA_API(uint64_t) 147 lzma_crc64(const uint8_t *buf, size_t size, uint64_t crc) 148 { 149 #if defined(_MSC_VER) && !defined(__INTEL_COMPILER) && !defined(__clang__) \ 150 && defined(_M_IX86) && defined(CRC64_ARCH_OPTIMIZED) 151 // VS2015-2022 might corrupt the ebx register on 32-bit x86 when 152 // the CLMUL code is enabled. This hack forces MSVC to store and 153 // restore ebx. This is only needed here, not in lzma_crc32(). 154 __asm mov ebx, ebx 155 #endif 156 157 #if defined(CRC64_GENERIC) && defined(CRC64_ARCH_OPTIMIZED) 158 return crc64_func(buf, size, crc); 159 160 #elif defined(CRC64_ARCH_OPTIMIZED) 161 // If arch-optimized version is used unconditionally without runtime 162 // CPU detection then omitting the generic version and its 8 KiB 163 // lookup table makes the library smaller. 164 return crc64_arch_optimized(buf, size, crc); 165 166 #else 167 return lzma_crc64_generic(buf, size, crc); 168 #endif 169 } 170