我正在尝试将最初为x86架构编写的代码移植到arm。
最初它是为msvc / win32开发的,代码中有很多错误,所以可能有UB。
代码在使用gcc编译时正在使用x86,但是在arm上它具有不同的行为。它似乎丢失了数组中的一些数据,武器开关不起作用。 它影响了服务器和客户端库。
应用程序是单线程的,因此不是同步问题。
默认情况下,char在arm上是无符号的,所以我将-fsigned-char
添加到编译器标志,但它没有解决问题。 arm和x86 c代码之间还有什么区别?
我尝试使用gcc和clang在arm上编译代码并且没有区别,因此它不是编译器错误。
P.S 我使用gcc-4.9(而不是4.8)编译了x86的代码并得到了相同的行为。 之后,我结合了两个编译器,发现问题出在net_encode.c。
当时,sebastien chevalier发现了
iValue /= pField->multiplier;
iValue *= pField->multiplier;
当iValue为整数且pField->乘数== 1.0f时,有时会更改整数值。
可以通过在乘法之前添加检查pField->乘数!= 1.0f来修复。
答案 0 :(得分:5)
如果没有看到你的代码几乎不可能说,但会尽力回答。
x86和ARM之间的一个巨大差异是大多数x86指令在内部都是原子的方式,而ARM没有这样的东西 - 你必须明确地说“只执行这组指令”。因此,如果您有多个线程更新的数据,这可能会打击您。
个别指令的行为方式也存在差异。在不知道你的代码做什么的情况下,这很难说是否会影响你的代码,但有一点可以解决的是“未对齐访问”,这在x86中是完全有效的(尽管不是最优的),但是无效(在大多数情况下) ARM处理器上的模型)。所以指针必须与它访问的项目的大小对齐。
当然,编译器中的代码生成也不同,可能会根据输入代码做出不同的决策,从而最终得到的代码在各种方式下表现不同。一次不止一次打击我的是“参数函数调用的执行顺序”:
func(func1(), func2());
请注意,func1()
或 func2()
可能会先执行。如果您依赖此类订购,则需要:
t1 = func1();
t2 = func2();
func(t1, t2);
提示:
如果您还没有,请尽可能多地启用警告(至少-Wall
)。并修正任何警告
检查#pragma pack
或类似的“数据包数据结构”,并类似地从char *
转换为int *
等,因为这些可能导致未对齐的访问问题。
编辑:当然,不同的编译器会有不同的错误,这些错误可能会或可能不会对特定的编译器,处理器和代码组合产生影响。虽然铿锵声不太可能也会产生相同的问题。
答案 1 :(得分:4)
我不是这方面的专家,但我可以指出一些一般性的事情。
首先,根据ARM的版本和设置,某些基本类型的大小,符号和字节顺序可能与x86(特别是x86_64)的不同。在这方面,编写良好的可移植代码不应该对任何这些方面做出假设。如果您需要特定尺寸和签名,请使用<cstdint>
/ <stdint.h>
标题中的类型。而endianness也是你应该照顾的东西。
其次,正如Mats所提到的,ARM和x86之间最臭名昭着和改变行为的差异之一就是内存模型的严格性。简而言之,x86往往非常保守(因此,本质上“安全”或至少不足为奇),而ARM则更弱(因此可能更快)。这对于并发代码尤其重要。默认情况下,x86上的许多基本操作都是原子操作,并且有许多隐含的完整内存栅栏可以保证一般的一致性。那些保护机制在ARM上默认不存在,这可能导致许多奇怪的行为。
例如,许多天真的多线程代码会错误地使用volatile
变量作为在线程之间共享信息或信号的方法。在许多情况下,由于其保守的内存模型,这将在x86上正常工作。但是在ARM体系结构中,该代码很可能会被破坏。
最后,总的来说,不同的架构在某些操作上的行为略有不同。所有这些差异通常属于标准的“未定义行为”或“实现定义”类别。这些是最难找到的错误,因为未定义的行为通常意味着在一个架构(和编译器)上会发生一件事情,这可能是正常的,但在另一个架构上,会发生其他事情,这可能不没关系。
有一些工具可以帮助您解决所有这些问题。主要工具是所谓的“消毒剂”。这些工具可以检测运行时代码,检查与所有这些相关的各种问题(例如,您可以使用工作的x86代码运行它们,并且它们指向可能在ARM上表现不同的“危险”事物或其他地方)。您可以尝试UBSan(未定义的行为清理程序,用于UB操作),TSan(线程清理程序,用于数据争用和危险的跨线程内存访问)和ASan(地址清理程序,用于内存)一般调试),这些都在Clang和GCC下都可用。我不知道这些工具是否有任何可以帮助ARM的特殊工具,或者它们是否甚至针对ARM,但至少,解决他们在x86上指出的任何问题都应该在将其移植到ARM时有很大帮助。