1 /* cksum -- calculate and print POSIX checksums and sizes of files
2 Copyright (C) 1992-2024 Free Software Foundation, Inc.
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <https://www.gnu.org/licenses/>. */
17 /* Written by Q. Frank Xia, qx@math.columbia.edu.
18 Cosmetic changes and reorganization by David MacKenzie, djm@gnu.ai.mit.edu.
20 Usage: cksum [file...]
22 The code segment between "#ifdef CRCTAB" and "#else" is the code
23 which calculates the "crctab". It is included for those who want
24 verify the correctness of the "crctab". To recreate the "crctab",
25 do something like the following:
27 cc -I../lib -DCRCTAB -o crctab cksum.c
30 This software is compatible with neither the System V nor the BSD
31 'sum' program. It is supposed to conform to POSIX, except perhaps
32 for foreign language support. Any inconsistency with the standard
33 (other than foreign language support) is a bug. */
38 #include <sys/types.h>
43 #ifdef USE_VMULL_CRC32
44 # include <sys/auxv.h>
45 # include <asm/hwcap.h>
50 # define BIT(x) ((uint_fast32_t) 1 << (x))
51 # define SBIT BIT (31)
53 /* The generating polynomial is
55 32 26 23 22 16 12 11 10 8 7 5 4 2 1
56 G(X)=X + X + X + X + X + X + X + X + X + X + X + X + X + X + 1
58 The i bit in GEN is set if X^i is a summand of G(X) except X^32. */
60 # define GEN (BIT (26) | BIT (23) | BIT (22) | BIT (16) | BIT (12) \
61 | BIT (11) | BIT (10) | BIT (8) | BIT (7) | BIT (5) \
62 | BIT (4) | BIT (2) | BIT (1) | BIT (0))
64 static uint_fast32_t r
[8];
70 for (int i
= 1; i
< 8; i
++)
71 r
[i
] = (r
[i
- 1] << 1) ^ ((r
[i
- 1] & SBIT
) ? GEN
: 0);
77 uint_fast32_t rem
= 0;
79 for (int i
= 0; i
< 8; i
++)
83 return rem
& 0xFFFFFFFF; /* Make it run on 64-bit machine. */
90 static uint_fast32_t crctab
[8][256];
94 for (i
= 0; i
< 256; i
++)
96 crctab
[0][i
] = crc_remainder (i
);
99 /* CRC(0x11 0x22 0x33 0x44)
101 CRC(0x11 0x00 0x00 0x00) XOR CRC(0x22 0x00 0x00) XOR
102 CRC(0x33 0x00) XOR CRC(0x44)
103 We precompute the CRC values for the offset values into
104 separate CRC tables. We can then use them to speed up
105 CRC calculation by processing multiple bytes at the time. */
106 for (i
= 0; i
< 256; i
++)
110 crc
= (crc
<< 8) ^ crctab
[0][((crc
>> 24) ^ (i
& 0xFF)) & 0xFF];
111 for (idx_t offset
= 1; offset
< 8; offset
++)
113 crc
= (crc
<< 8) ^ crctab
[0][((crc
>> 24) ^ 0x00) & 0xFF];
114 crctab
[offset
][i
] = crc
;
118 printf ("#include <config.h>\n");
119 printf ("#include <stdint.h>\n");
120 printf ("#include <stdio.h>\n");
121 printf ("#include \"cksum.h\"\n");
123 printf ("uint_fast32_t const crctab[8][256] = {\n");
124 for (int y
= 0; y
< 8; y
++)
126 printf ("{\n 0x%08x", crctab
[y
][0]);
127 for (i
= 0; i
< 51; i
++)
129 printf (",\n 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x",
130 crctab
[y
][i
* 5 + 1], crctab
[y
][i
* 5 + 2],
131 crctab
[y
][i
* 5 + 3], crctab
[y
][i
* 5 + 4],
132 crctab
[y
][i
* 5 + 5]);
145 /* Number of bytes to read at once. */
146 # define BUFLEN (1 << 16)
149 pclmul_supported (void)
151 bool pclmul_enabled
= false;
152 # if USE_PCLMUL_CRC32 || GL_CRC_X86_64_PCLMUL
153 pclmul_enabled
= (0 < __builtin_cpu_supports ("pclmul")
154 && 0 < __builtin_cpu_supports ("avx"));
159 ? _("using pclmul hardware support")
160 : _("pclmul support not detected")));
163 return pclmul_enabled
;
167 avx2_supported (void)
169 /* AVX512 processors will not set vpclmulqdq unless they support
170 the avx512 version, but it implies that the avx2 version
172 bool avx2_enabled
= false;
174 avx2_enabled
= (0 < __builtin_cpu_supports ("vpclmulqdq")
175 && 0 < __builtin_cpu_supports ("avx2"));
180 ? _("using avx2 hardware support")
181 : _("avx2 support not detected")));
188 avx512_supported (void)
190 /* vpclmulqdq for multiplication
191 mavx512f for most of the avx512 functions we're using
192 mavx512bw for byte swapping */
193 bool avx512_enabled
= false;
194 # if USE_AVX512_CRC32
195 avx512_enabled
= (0 < __builtin_cpu_supports ("vpclmulqdq")
196 && 0 < __builtin_cpu_supports ("avx512bw")
197 && 0 < __builtin_cpu_supports ("avx512f"));
202 ? _("using avx512 hardware support")
203 : _("avx512 support not detected")));
206 return avx512_enabled
;
210 vmull_supported (void)
212 /* vmull for multiplication */
213 bool vmull_enabled
= false;
216 vmull_enabled
= (getauxval (AT_HWCAP
) & HWCAP_PMULL
) > 0;
221 ? _("using vmull hardware support")
222 : _("vmull support not detected")));
225 return vmull_enabled
;
229 cksum_slice8 (FILE *fp
, uint_fast32_t *crc_out
, uintmax_t *length_out
)
231 uint32_t buf
[BUFLEN
/ sizeof (uint32_t)];
232 uint_fast32_t crc
= 0;
233 uintmax_t length
= 0;
236 if (!fp
|| !crc_out
|| !length_out
)
239 while ((bytes_read
= fread (buf
, 1, BUFLEN
, fp
)) > 0)
243 if (length
+ bytes_read
< length
)
248 length
+= bytes_read
;
250 /* Process multiples of 8 bytes */
251 datap
= (uint32_t *)buf
;
252 while (bytes_read
>= 8)
254 uint32_t first
= *datap
++, second
= *datap
++;
255 crc
^= htobe32 (first
);
256 second
= htobe32 (second
);
257 crc
= (crctab
[7][(crc
>> 24) & 0xFF]
258 ^ crctab
[6][(crc
>> 16) & 0xFF]
259 ^ crctab
[5][(crc
>> 8) & 0xFF]
260 ^ crctab
[4][(crc
) & 0xFF]
261 ^ crctab
[3][(second
>> 24) & 0xFF]
262 ^ crctab
[2][(second
>> 16) & 0xFF]
263 ^ crctab
[1][(second
>> 8) & 0xFF]
264 ^ crctab
[0][(second
) & 0xFF]);
268 /* And finish up last 0-7 bytes in a byte by byte fashion */
269 unsigned char *cp
= (unsigned char *)datap
;
271 crc
= (crc
<< 8) ^ crctab
[0][((crc
>> 24) ^ *cp
++) & 0xFF];
277 *length_out
= length
;
282 /* Calculate the checksum and length in bytes of stream STREAM.
283 Return -1 on error, 0 on success. */
286 crc_sum_stream (FILE *stream
, void *resstream
, uintmax_t *length
)
288 uintmax_t total_bytes
= 0;
289 uint_fast32_t crc
= 0;
291 static bool (*cksum_fp
) (FILE *, uint_fast32_t *, uintmax_t *);
294 if (avx512_supported ())
295 cksum_fp
= cksum_avx512
;
296 else if (avx2_supported ())
297 cksum_fp
= cksum_avx2
;
298 else if (pclmul_supported ())
299 cksum_fp
= cksum_pclmul
;
300 else if (vmull_supported ())
301 cksum_fp
= cksum_vmull
;
303 cksum_fp
= cksum_slice8
;
306 if (! cksum_fp (stream
, &crc
, &total_bytes
))
309 *length
= total_bytes
;
311 for (; total_bytes
; total_bytes
>>= 8)
312 crc
= (crc
<< 8) ^ crctab
[0][((crc
>> 24) ^ total_bytes
) & 0xFF];
313 crc
= ~crc
& 0xFFFFFFFF;
315 unsigned int crc_out
= crc
;
316 memcpy (resstream
, &crc_out
, sizeof crc_out
);
321 /* Calculate the crc32b checksum and length in bytes of stream STREAM.
322 Return -1 on error, 0 on success. */
325 crc32b_sum_stream (FILE *stream
, void *resstream
, uintmax_t *reslen
)
327 uint32_t buf
[BUFLEN
/ sizeof (uint32_t)];
332 if (!stream
|| !resstream
|| !reslen
)
335 # if GL_CRC_X86_64_PCLMUL
337 (void) pclmul_supported ();
340 while ((bytes_read
= fread (buf
, 1, BUFLEN
, stream
)) > 0)
342 if (len
+ bytes_read
< len
)
349 crc
= crc32_update (crc
, (char const *)buf
, bytes_read
);
355 unsigned int crc_out
= crc
;
356 memcpy (resstream
, &crc_out
, sizeof crc_out
);
360 return ferror (stream
) ? -1 : 0;
363 /* Print the checksum and size to stdout.
364 If ARGS is true, also print the FILE name. */
367 output_crc (char const *file
, int binary_file
, void const *digest
, bool raw
,
368 bool tagged
, unsigned char delim
, bool args
, uintmax_t length
)
372 /* Output in network byte order (big endian). */
373 uint32_t out_int
= htobe32 (*(uint32_t *)digest
);
374 fwrite (&out_int
, 1, 32/8, stdout
);
378 printf ("%u %ju", *(unsigned int *)digest
, length
);
380 printf (" %s", file
);