C代码从x86迁移到ARM需要注意的点

最近工作中遇到的一个问题,PHPhash算法在x86下和ARM下计算结果不一样:

1
2
3
4
5
6
static zend_always_inline zend_ulong zend_inline_hash_func(const char *str, size_t len)
{
// 省略其他代码
hash = ((hash << 5) + hash) + *str++;
// 省略其他代码
}

这里会对str进行处理。在x86下面,char默认是signed的;在ARM下,charunsigned的。那么,就有可能出现strx86下是负数,在ARM下是正数。

这个问题,可以通过添加编译器的-fsigned-char选项得到解决。加在PHPMakefileCFLAGS后面即可:

1
CFLAGS = $(CFLAGS_CLEAN) -prefer-non-pic -static -fsigned-char

当然,我们也可以显式的定义strsigned

除了这个问题之外,还有其他的差异:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
graph-easy <<< "
[
info\n
Explicitly define a variable of type char to be signed.
] ->
[
x86 code\n
char c = '*';
] ->
[
ARM code\n
signed c = '*';
]

[
info\n
Use the builtin function that comes with the compiler.
] ->
[
x86 code\n
__builtin_ia32_crc32qi(__a, __b);
] ->
[
ARM code\n
__builtin_aarch64_crc32b(__a, __b);
]

[
info\n
prefetch memory data into the cache.
] ->
[
x86 code\n
asm volatile(""prefetcht0 %0""::""m"" (*(unsigned long *)x));
] ->
[
ARM code\n
define prefetch(_x) __builtin_prefetch(_x);
]

[
info\n
define the compiled program to be 64-bit.
] ->
[
x86 code\n
-m64;
] ->
[
ARM code\n
-mabi=lp64;
]

[
info\n
the instruction set type is defined in the Makefile, from x86 to ARM.
] ->
[
x86 code\n
-march=broadwell;
] ->
[
ARM code\n
-march=armv8-a;
]

[
info\n
replace the original x86 version of the compiled macros with the ARM version.
] ->
[
x86 code\n
__X86_64__;
] ->
[
ARM code\n
__ARM_64__;
]
"

+-------------------------------------------------------------------------------+ +-------------------------------------------------------+ +---------------------------------------------+
| info | | x86 code | | ARM code |
| Explicitly define a variable of type char to be signed. | --> | char c = '*'; | --> | signed c = '*'; |
+-------------------------------------------------------------------------------+ +-------------------------------------------------------+ +---------------------------------------------+
+-------------------------------------------------------------------------------+ +-------------------------------------------------------+ +---------------------------------------------+
| info | | x86 code | | ARM code |
| Use the builtin function that comes with the compiler. | --> | __builtin_ia32_crc32qi(__a, __b); | --> | __builtin_aarch64_crc32b(__a, __b); |
+-------------------------------------------------------------------------------+ +-------------------------------------------------------+ +---------------------------------------------+
+-------------------------------------------------------------------------------+ +-------------------------------------------------------+ +---------------------------------------------+
| info | | x86 code | | ARM code |
| define the compiled program to be 64-bit. | --> | -m64; | --> | -mabi=lp64; |
+-------------------------------------------------------------------------------+ +-------------------------------------------------------+ +---------------------------------------------+
+-------------------------------------------------------------------------------+ +-------------------------------------------------------+ +---------------------------------------------+
| info | | x86 code | | ARM code |
| prefetch memory data into the cache. | --> | asm volatile(prefetcht0 %0::m (*(unsigned long *)x)); | --> | define prefetch(_x) __builtin_prefetch(_x); |
+-------------------------------------------------------------------------------+ +-------------------------------------------------------+ +---------------------------------------------+
+-------------------------------------------------------------------------------+ +-------------------------------------------------------+ +---------------------------------------------+
| info | | x86 code | | ARM code |
| replace the original x86 version of the compiled macros with the ARM version. | --> | __X86_64__; | --> | __ARM_64__; |
+-------------------------------------------------------------------------------+ +-------------------------------------------------------+ +---------------------------------------------+
+-------------------------------------------------------------------------------+ +-------------------------------------------------------+ +---------------------------------------------+
| info | | x86 code | | ARM code |
| the instruction set type is defined in the Makefile, from x86 to ARM. | --> | -march=broadwell; | --> | -march=armv8-a; |
+-------------------------------------------------------------------------------+ +-------------------------------------------------------+ +---------------------------------------------+