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