【问题标题】:Android native Code crashes in thumb mode but but not in arm modeAndroid 本机代码在拇指模式下崩溃,但在手臂模式下不崩溃
【发布时间】:2012-04-02 11:55:01
【问题描述】:

我正在尝试使用 android NDK 为 android 平台编译和运行本机代码。 在代码中的许多地方,我试图将一个短整数指针转换为一个整数指针,因此尽管它与 X86 一起正常工作,但它存在内存对齐问题。我正在以拇指模式编译代码,由于如上所述的未对齐访问,代码正在运行。但是如果我在 ARM 模式下编译代码,它不会崩溃并正常工作。

我的疑问是为什么代码在 arm 模式编译中没有崩溃,尽管它存在内存对齐问题。

我对 ARM 和 THUMB 指令集知之甚少。我知道 ARM 指令集是 32 位宽,拇指是 16 位宽。但它对未对齐的访问有何影响?

【问题讨论】:

    标签: android-ndk arm


    【解决方案1】:

    我认为崩溃不是由指令编码长度引起的。 ARM 和 Thumb 模式应该具有从对齐或非对齐地址加载 数据 的相同能力。

    首先,您使用的是真正不允许未对齐 32 位加载的真正 ARMv5 硬件吗?因为较新的 ARM 芯片,例如运行为 ARMv5TE 编译的 Android 的 ARMv6 (ARM11) 芯片,可以执行未对齐的 32 位加载并且不会崩溃。当然,如果你的 manifest 声明它是为 ARMv5TE 编译的,那么在真正的 ARMv5 硬件上运行的 Android 设备会很高兴地安装它并崩溃——你有责任确保你的应用真正与其声称的兼容。

    Qemu(包括 Android SDK 中捆绑的模拟器)在模拟arm926ej-s (ARMv5TEJ) 芯片时正确模拟未对齐的 32 位加载时崩溃。你不能依靠模拟器来捕捉它。在这方面,它真的只对 Java 开发有好处。

    你能看到 gdb 中的崩溃吗?你能显示寄存器转储并查看来自未对齐地址的负载吗?您确定编译器不会(以允许的方式)更改代码的含义吗?

    对于 x86 以外的可移植性,您实际上不应该执行从 uint16_t*uint32_t* 的转换。 C 语言不保证它们可以工作。从技术上讲,您的代码总是“错误的”。看看野外的可移植代码:它使用预处理器宏或静态内联函数来抽象出诸如“get_unaligned_le32”之类的概念或 x86 上依赖未对齐访问的整个函数。

    【讨论】:

    • 非常感谢您的回复,
    【解决方案2】:

    Thumb 指令的长度为 16 位,而 ARM 的指令大小为 32 位。

    这意味着在 ARM 模式下,保证代码中的数据部分是 4 字节对齐的,但在 Thumb 模式下则不然。

    您可以尝试对齐指令。对齐语法因编译器/汇编器而异。

    某些库中的某些(依赖于硬件的)例程假定数据是 4 字节对齐的,无论数据类型如何。 如果不满足此条件,它要么崩溃,要么性能严重受损。

    此外,如果您将缓存考虑在内,则最好还是对齐性能关键数据。缓存友好的对齐方式因 SoC 而异,但通常在 ARM11 上为 32 字节,在 Coretex 上为 64 字节。

    【讨论】:

    • 我也有疑问,崩溃是否总是定义错误的内存访问的结果,或者它可能不会崩溃?由于在我的代码中有许多指针未对齐地址,但代码崩溃时只有几个指针并非全部,所以请让我知道您的 cmets。
    • 在拇指模式下,数据有 50% 的几率是 4 字节对齐的。这解释了不一致。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-20
    • 2023-03-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多