xref: /PHP-7.4/ext/standard/crc32.c (revision d4bebc87)
1 /*
2    +----------------------------------------------------------------------+
3    | PHP Version 7                                                        |
4    +----------------------------------------------------------------------+
5    | Copyright (c) The PHP Group                                          |
6    +----------------------------------------------------------------------+
7    | This source file is subject to version 3.01 of the PHP license,      |
8    | that is bundled with this package in the file LICENSE, and is        |
9    | available through the world-wide-web at the following url:           |
10    | http://www.php.net/license/3_01.txt                                  |
11    | If you did not receive a copy of the PHP license and are unable to   |
12    | obtain it through the world-wide-web, please send a note to          |
13    | license@php.net so we can mail you a copy immediately.               |
14    +----------------------------------------------------------------------+
15    | Author: Rasmus Lerdorf <rasmus@php.net>                              |
16    +----------------------------------------------------------------------+
17 */
18 
19 #include "php.h"
20 #include "basic_functions.h"
21 #include "crc32.h"
22 
23 #if HAVE_AARCH64_CRC32
24 # include <arm_acle.h>
25 # if defined(__linux__)
26 #  include <sys/auxv.h>
27 #  include <asm/hwcap.h>
28 # endif
29 
has_crc32_insn()30 static inline int has_crc32_insn() {
31 	/* Only go through the runtime detection once. */
32 	static int res = -1;
33 	if (res != -1)
34 		return res;
35 # if defined(HWCAP_CRC32)
36 	res = getauxval(AT_HWCAP) & HWCAP_CRC32;
37 	return res;
38 # elif defined(HWCAP2_CRC32)
39 	res = getauxval(AT_HWCAP2) & HWCAP2_CRC32;
40 	return res;
41 # else
42 	res = 0;
43 	return res;
44 # endif
45 }
46 
47 # pragma GCC push_options
48 # pragma GCC target ("+nothing+crc")
crc32_aarch64(uint32_t crc,char * p,size_t nr)49 static uint32_t crc32_aarch64(uint32_t crc, char *p, size_t nr) {
50 	while (nr >= sizeof(uint64_t)) {
51 		crc = __crc32d(crc, *(uint64_t *)p);
52 		p += sizeof(uint64_t);
53 		nr -= sizeof(uint64_t);
54 	}
55 	if (nr >= sizeof(int32_t)) {
56 		crc = __crc32w(crc, *(uint32_t *)p);
57 		p += sizeof(uint32_t);
58 		nr -= sizeof(uint32_t);
59 	}
60 	if (nr >= sizeof(int16_t)) {
61 		crc = __crc32h(crc, *(uint16_t *)p);
62 		p += sizeof(uint16_t);
63 		nr -= sizeof(uint16_t);
64 	}
65 	if (nr) {
66 		crc = __crc32b(crc, *p);
67 	}
68 	return crc;
69 }
70 # pragma GCC pop_options
71 #endif
72 
73 /* {{{ proto string crc32(string str)
74    Calculate the crc32 polynomial of a string */
PHP_NAMED_FUNCTION(php_if_crc32)75 PHP_NAMED_FUNCTION(php_if_crc32)
76 {
77 	char *p;
78 	size_t nr;
79 	uint32_t crcinit = 0;
80 	register uint32_t crc;
81 
82 	ZEND_PARSE_PARAMETERS_START(1, 1)
83 		Z_PARAM_STRING(p, nr)
84 	ZEND_PARSE_PARAMETERS_END();
85 
86 	crc = crcinit^0xFFFFFFFF;
87 
88 #if HAVE_AARCH64_CRC32
89 	if (has_crc32_insn()) {
90 		crc = crc32_aarch64(crc, p, nr);
91 		RETURN_LONG(crc^0xFFFFFFFF);
92 	}
93 #endif
94 
95 	for (; nr--; ++p) {
96 		crc = ((crc >> 8) & 0x00FFFFFF) ^ crc32tab[(crc ^ (*p)) & 0xFF ];
97 	}
98 	RETURN_LONG(crc^0xFFFFFFFF);
99 }
100 /* }}} */
101