我正在尝试使用android NDK编译和运行Android平台的本机代码。 在代码中的许多地方我试图将一个短整数指针强制转换为整数指针,因此虽然它与X86一起正常工作但它有内存对齐问题。我正在以拇指模式编译代码,代码是因为如上所述的未对齐访问而进行的。但是如果我在ARM模式下编译代码,它就不会崩溃并且工作正常。
我怀疑为什么代码在arm模式编译时没有崩溃,尽管它有内存对齐问题。
我对ARM和THUMB指令集知之甚少。我知道ARM指令集是32位宽,拇指是16位宽。但是如何关注未对齐访问呢?
答案 0 :(得分:2)
我认为崩溃不是由指令编码长度引起的。 ARM和Thumb模式应具有从对齐或未对齐地址加载数据的相同功能。
首先,您使用真正不允许未对齐32位负载的真正ARMv5硬件吗?因为较新的ARM芯片,例如运行为ARMv5TE编译的Android的ARMv6(ARM11)芯片,可以执行未对齐的32位负载并且不会崩溃。当然,如果您的清单声明它是为ARMv5TE编译的,那么在真正的ARMv5硬件上运行的Android设备将很乐意安装并崩溃 - 您有责任确保您的应用与其声称的内容完全兼容。
Qemu(包括Android SDK中捆绑的模拟器)在模拟arm926ej-s(ARMv5TEJ)芯片时,不正确模拟未对齐的32位负载上的崩溃。你不能依靠模拟器来捕获它。在这方面,这对Java开发来说真的很有用。你能看到gdb中的崩溃吗?你能显示寄存器转储并查看未对齐地址的负载吗?您确定编译器不会改变代码的含义(以允许的方式)吗?
对于超出x86的可移植性,您实际上不应该执行从uint16_t*
到uint32_t*
的强制转换。 C语言并不能保证它们能够正常工作。从技术上讲,你的代码总是“错误的”。在野外查看可移植代码:它使用预处理器宏或静态内联函数来抽象出像“get_unaligned_le32”这样的概念或x86依赖于未对齐访问的整个函数。
答案 1 :(得分:0)
Thumb指令的长度为16位,而ARM的大小为32位。
这意味着在ARM模式下,可以保证代码中的数据部分是4字节对齐,但不是在Thumb模式下。
您可以尝试对齐指令。对齐语法因编译器/汇编程序而异。
某些库中的某些(硬件相关)例程假定数据是4字节对齐,而不管数据类型如何。 如果不满足此条件,则会导致崩溃或性能严重下降。
此外,如果您考虑缓存,那么无论如何都要对齐性能关键数据。缓存友好的对齐方式因SoC而异,但在ARM11上通常为32byte,在Coretex上为64byte。