| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| |
| |
| #ifndef CRCTAB |
| # include <config.h> |
| #endif |
|
|
| #ifdef CRCTAB |
|
|
| # include <stdio.h> |
|
|
| # define BIT(x) (1u << (x)) |
| # define SBIT BIT (31) |
|
|
| |
| |
| |
| |
| |
| |
|
|
| # define GEN (BIT (26) | BIT (23) | BIT (22) | BIT (16) | BIT (12) \ |
| | BIT (11) | BIT (10) | BIT (8) | BIT (7) | BIT (5) \ |
| | BIT (4) | BIT (2) | BIT (1) | BIT (0)) |
|
|
| static unsigned int r[8]; |
|
|
| static void |
| fill_r (void) |
| { |
| r[0] = GEN; |
| for (int i = 1; i < 8; i++) |
| r[i] = (r[i - 1] << 1) ^ ((r[i - 1] & SBIT) ? GEN : 0); |
| } |
|
|
| static unsigned int |
| crc_remainder (int m) |
| { |
| unsigned int rem = 0; |
|
|
| for (int i = 0; i < 8; i++) |
| if (BIT (i) & m) |
| rem ^= r[i]; |
|
|
| return rem & 0xFFFFFFFF; |
| } |
|
|
| int |
| main (void) |
| { |
| static unsigned int crctab[8][256]; |
|
|
| fill_r (); |
|
|
| for (int i = 0; i < 256; i++) |
| crctab[0][i] = crc_remainder (i); |
|
|
| |
| |
| |
| |
| |
| |
| |
| for (int i = 0; i < 256; i++) |
| { |
| unsigned int crc = 0; |
|
|
| crc = (crc << 8) ^ crctab[0][((crc >> 24) ^ i) & 0xFF]; |
| for (int offset = 1; offset < 8; offset++) |
| { |
| crc = (crc << 8) ^ crctab[0][((crc >> 24) ^ 0) & 0xFF]; |
| crctab[offset][i] = crc & 0xFFFFFFFF; |
| } |
| } |
|
|
| printf ("#include <config.h>\n"); |
| printf ("#include \"cksum.h\"\n"); |
| printf ("\n"); |
| printf ("uint_fast32_t const crctab[8][256] = {\n"); |
| for (int y = 0; y < 8; y++) |
| { |
| printf ("{\n 0x%08x", crctab[y][0]); |
| for (int i = 0; i < 51; i++) |
| { |
| printf (",\n 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x", |
| crctab[y][i * 5 + 1], crctab[y][i * 5 + 2], |
| crctab[y][i * 5 + 3], crctab[y][i * 5 + 4], |
| crctab[y][i * 5 + 5]); |
| } |
| printf ("\n},\n"); |
| } |
| printf ("};\n"); |
| } |
|
|
| #else |
|
|
| # include "cksum.h" |
| # include <sys/types.h> |
| # include <endian.h> |
| # include "system.h" |
|
|
| # ifdef USE_VMULL_CRC32 |
| # include <sys/auxv.h> |
| # include <asm/hwcap.h> |
| # endif |
|
|
| # include "crc.h" |
| # include "cpu-supports.h" |
|
|
| |
| # define BUFLEN (1 << 16) |
|
|
| typedef bool (*cksum_fp_t) (FILE *, uint_fast32_t *, uintmax_t *); |
|
|
| static cksum_fp_t |
| pclmul_supported (void) |
| { |
| # if USE_PCLMUL_CRC32 || GL_CRC_X86_64_PCLMUL |
| bool pclmul_enabled = (cpu_supports ("avx") |
| && cpu_supports ("pclmul")); |
| if (cksum_debug) |
| error (0, 0, "%s", |
| (pclmul_enabled |
| ? _("using pclmul hardware support") |
| : _("pclmul support not detected"))); |
| # if USE_PCLMUL_CRC32 |
| if (pclmul_enabled) |
| return cksum_pclmul; |
| # endif |
| # endif |
|
|
| return nullptr; |
| } |
|
|
| static cksum_fp_t |
| avx2_supported (void) |
| { |
| |
| |
| |
| # if USE_AVX2_CRC32 |
| bool avx2_enabled = (cpu_supports ("avx2") |
| && cpu_supports ("vpclmulqdq")); |
| if (cksum_debug) |
| error (0, 0, "%s", |
| (avx2_enabled |
| ? _("using avx2 hardware support") |
| : _("avx2 support not detected"))); |
| if (avx2_enabled) |
| return cksum_avx2; |
| # endif |
|
|
| return nullptr; |
| } |
|
|
| static cksum_fp_t |
| avx512_supported (void) |
| { |
| |
| |
| |
| # if USE_AVX512_CRC32 |
| bool avx512_enabled = (cpu_supports ("avx512f") |
| && cpu_supports ("avx512bw") |
| && cpu_supports ("vpclmulqdq")); |
|
|
| if (cksum_debug) |
| error (0, 0, "%s", |
| (avx512_enabled |
| ? _("using avx512 hardware support") |
| : _("avx512 support not detected"))); |
| if (avx512_enabled) |
| return cksum_avx512; |
| # endif |
|
|
| return nullptr; |
| } |
|
|
| static cksum_fp_t |
| vmull_supported (void) |
| { |
| |
| # if USE_VMULL_CRC32 |
| bool vmull_enabled = (cpu_may_support ("pmull") |
| && (getauxval (AT_HWCAP) & HWCAP_PMULL) > 0); |
| if (cksum_debug) |
| error (0, 0, "%s", |
| (vmull_enabled |
| ? _("using vmull hardware support") |
| : _("vmull support not detected"))); |
| if (vmull_enabled) |
| return cksum_vmull; |
| # endif |
|
|
| return nullptr; |
| } |
|
|
| static bool |
| cksum_slice8 (FILE *fp, uint_fast32_t *crc_out, uintmax_t *length_out) |
| { |
| uint32_t buf[BUFLEN / sizeof (uint32_t)]; |
| uint_fast32_t crc = 0; |
| uintmax_t length = 0; |
| size_t bytes_read; |
|
|
| if (!fp || !crc_out || !length_out) |
| return false; |
|
|
| while ((bytes_read = fread (buf, 1, BUFLEN, fp)) > 0) |
| { |
| uint32_t *datap; |
|
|
| if (length + bytes_read < length) |
| { |
| errno = EOVERFLOW; |
| return false; |
| } |
| length += bytes_read; |
|
|
| |
| datap = (uint32_t *)buf; |
| while (bytes_read >= 8) |
| { |
| uint32_t first = *datap++, second = *datap++; |
| crc ^= htobe32 (first); |
| second = htobe32 (second); |
| crc = (crctab[7][(crc >> 24) & 0xFF] |
| ^ crctab[6][(crc >> 16) & 0xFF] |
| ^ crctab[5][(crc >> 8) & 0xFF] |
| ^ crctab[4][(crc) & 0xFF] |
| ^ crctab[3][(second >> 24) & 0xFF] |
| ^ crctab[2][(second >> 16) & 0xFF] |
| ^ crctab[1][(second >> 8) & 0xFF] |
| ^ crctab[0][(second) & 0xFF]); |
| bytes_read -= 8; |
| } |
|
|
| |
| unsigned char *cp = (unsigned char *)datap; |
| while (bytes_read--) |
| crc = (crc << 8) ^ crctab[0][((crc >> 24) ^ *cp++) & 0xFF]; |
| if (feof (fp)) |
| break; |
| } |
|
|
| *crc_out = crc; |
| *length_out = length; |
|
|
| return !ferror (fp); |
| } |
|
|
| |
| |
|
|
| int |
| crc_sum_stream (FILE *stream, void *resstream, uintmax_t *length) |
| { |
| uintmax_t total_bytes = 0; |
| uint_fast32_t crc = 0; |
|
|
| static cksum_fp_t cksum_fp; |
| if (! cksum_fp) |
| cksum_fp = avx512_supported (); |
| if (! cksum_fp) |
| cksum_fp = avx2_supported (); |
| if (! cksum_fp) |
| cksum_fp = pclmul_supported (); |
| if (! cksum_fp) |
| cksum_fp = vmull_supported (); |
| if (! cksum_fp) |
| cksum_fp = cksum_slice8; |
|
|
| if (! cksum_fp (stream, &crc, &total_bytes)) |
| return -1; |
|
|
| *length = total_bytes; |
|
|
| for (; total_bytes; total_bytes >>= 8) |
| crc = (crc << 8) ^ crctab[0][((crc >> 24) ^ total_bytes) & 0xFF]; |
| crc = ~crc & 0xFFFFFFFF; |
|
|
| unsigned int crc_out = crc; |
| memcpy (resstream, &crc_out, sizeof crc_out); |
|
|
| return 0; |
| } |
|
|
| |
| |
|
|
| int |
| crc32b_sum_stream (FILE *stream, void *resstream, uintmax_t *reslen) |
| { |
| uint32_t buf[BUFLEN / sizeof (uint32_t)]; |
| uint32_t crc = 0; |
| uintmax_t len = 0; |
| size_t bytes_read; |
|
|
| if (!stream || !resstream || !reslen) |
| return -1; |
|
|
| # if GL_CRC_X86_64_PCLMUL |
| if (cksum_debug) |
| (void) pclmul_supported (); |
| # endif |
|
|
| while ((bytes_read = fread (buf, 1, BUFLEN, stream)) > 0) |
| { |
| if (len + bytes_read < len) |
| { |
| errno = EOVERFLOW; |
| return -1; |
| } |
| len += bytes_read; |
|
|
| crc = crc32_update (crc, (char const *)buf, bytes_read); |
|
|
| if (feof (stream)) |
| break; |
| } |
|
|
| unsigned int crc_out = crc; |
| memcpy (resstream, &crc_out, sizeof crc_out); |
|
|
| *reslen = len; |
|
|
| return ferror (stream) ? -1 : 0; |
| } |
|
|
| |
| |
|
|
| void |
| output_crc (char const *file, MAYBE_UNUSED int binary_file, |
| void const *digest, bool raw, MAYBE_UNUSED bool tagged, |
| unsigned char delim, bool args, uintmax_t length) |
| { |
| if (raw) |
| { |
| |
| uint32_t out_int = htobe32 (*(uint32_t *)digest); |
| fwrite (&out_int, 1, 32/8, stdout); |
| return; |
| } |
|
|
| printf ("%u %ju", *(unsigned int *)digest, length); |
| if (args) |
| printf (" %s", file); |
| putchar (delim); |
| } |
|
|
| #endif |
|
|