【问题标题】:ARM/Thumb interworking in assembly汇编中的 ARM/Thumb 互通
【发布时间】:2013-08-18 05:39:21
【问题描述】:

我正在构建一个 Windows Phone 项目,其中的一些部分正在组装中。我的程序集文件处于 ARM 模式 (CODE32),它会尝试跳转到我知道已编译为 Thumb 的 C 函数。代码如下:

    ldr r12, [pFunc]
    mov pc, r12
pFunc
    dcd My_C_Function

这是奇怪的事情。 sn-p 中pFunc 的值是指向函数thunk 的指针加一。也就是说,第 0 位被设置,好像跳转目标是 Thumb,跳转指令是 BX。但重击显然是 ARM! thunk 加载函数体的地址加一并对其执行 BX,正确切换模式。

尝试 BX 到该地址可能会崩溃,因为这会切换模式并尝试在 Thumb 模式下执行 ARM 代码不是一个好主意。尝试简单地跳转到该地址(就像当前代码一样)也可能会崩溃,因为 PC 最终会未对齐。

理论上,我可以手动清理第 0 位然后跳转,但我的想法肯定有一些错误。 thunk 是由 C 编译器生成的 - 对吧? C 编译器知道 thunk 是 ARM 代码。 pFunc 下的地址是由链接器生成的,因为它是一个跨模块调用。所以低位被链接器放在那里;为什么链接器不知道这些 thunk 是 ARM?

请解释一下?

我现在没有 WP8 设备,所以无法在真实硬件中试用。盯着生成的代码是我唯一的调试技巧:(

编辑:但是如果这些 thunk 不是 ARM,而是 Thumb-2 怎么办? Thumb-2 支持一些 32 位命令 IIRC。它们的编码是否与 ARM 模式相同?无论如何,Thumb-2 如何解码命令?

【问题讨论】:

  • 如果您已经在汇编中定义了所有标签(使用 gnu 汇编器,您在拇指标签之前使用 .thumb_func,不确定如何使用其他工具链执行此操作),并且 C 应该自行处理.从那里,汇编器、编译器和链接器将根据目的地注意 bx 到偶数或奇数地址。
  • 汇编器是 MASM 的 ARM 风格。我会检查我是否可以相应地装饰标签。但在一般情况下,理论上我可能不知道其他对象文件处于什么模式。如果它们是第三方对象怎么办?我希望链接器对此很聪明。
  • 这是我的观点,我希望链接器对此很聪明,如果您有反汇编器来检查并确保工具正确,请使用反汇编器。
  • 这正是我正在做的,缺少设备。

标签: assembly arm windows-phone thumb


【解决方案1】:

您想要的详细信息在“ARM 架构参考手册,ARMv7-A 和 ARMv7-R 版”的“A2.3.2 ARM 内核寄存器操作的伪代码详细信息”部分中指定。以下是有关写入 PC 寄存器的相关伪代码(来自上述手册):

BXWritePC(bits(32) address)
    if CurrentInstrSet() == InstrSet_ThumbEE then
        if address<0> == '1' then
            BranchTo(address<31:1>:'0');  // Remaining in ThumbEE state
        else
            UNPREDICTABLE;
    else
        if address<0> == '1' then
            SelectInstrSet(InstrSet_Thumb);
            BranchTo(address<31:1>:'0');
        elsif address<1> == '0' then
            SelectInstrSet(InstrSet_ARM);
            BranchTo(address);
        else // address<1:0> == '10'
            UNPREDICTABLE;

如果地址的低位(bit 0)被置位,处理器将清除该位,切换到Thumb模式,并执行跳转到新地址。

此行为适用于 ARMv7 及更高版本(即适用于所有 Windows Phone 设备,但并非所有 Android/iOS 设备)。

【讨论】:

  • 这证实了我对代码的怀疑,但没有解释为什么链接器会写一个指向 ARMy 目标的 Thumby 指针。是链接器吧?
  • 您问题中被误解的部分是Trying to simply jump to that address (as the current code does) would probably crash too, because PC would end up unaligned.。正如上述伪代码所暗示的,处理器会自动清除最低位,并仅将其用作切换到 Thumb 模式的指示。
  • IDK 哪个工具负责在 Windows Phone 上的函数指针中设置位 0,它可以是静态链接器(导出的 Thumb 函数的地址将设置位 0)或加载器(它可以使用元信息关于 Thumb 函数在导入表的指针中设置位 0)。实际上,差别不大。
  • 我正在查看文件中的 DLL 代码,而不是正在执行的代码。装载机还没有机会:)
【解决方案2】:

您的手上可能有一个有效/实际的问题。 Afaik Windows Phone 环境为required to be Thumb-2 only,因此您使用的链接器可能无法处理对 ARM 模式的调用。在混合汇编和 C 时,请参阅相同的链接以了解一些注意事项。

如果这是一个 Linux / ELF 问题,我会做出不同的回答;

pFunc 下的地址是由链接器生成的,因为它是一个跨模块调用。所以低位被链接器放在那里。

pFunccompiler 生成,linker 将在您构建可加载图像时修复它,该图像已经完全解决了调用的静态重定位问题。所有可移植目标文件都应包含有关功能模式的表,以便以后的链接器可以处理它们并相应地进行重定位和更新调用序列。

请参阅 ELF for the ARM Architecture - 4.6 Relocation 了解如何通过 ELF 文件完成此操作。

【讨论】:

  • 相关引用:“汇编器在代码段中设置符号的每个字的 LSB,因为它将它们解释为目标指令。”听起来可能就是这样。
【解决方案3】:

反汇编程序(特别是 IDA Demo)通过将多个命令合并到一行来误导我。它从 mov-orr-orr 序列中生成了一条 mov 行,该序列旨在将完整的 32 位常量分配给寄存器。 thunk 毕竟是拇指。链接器按设计工作。

IDA 在其他方面很棒。我对这种与 ARM 相关的特殊行为深有体会,但这次它滑倒了。

我的错,感谢所有试图提供帮助的人。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-03-28
    • 2014-07-10
    • 1970-01-01
    • 1970-01-01
    • 2022-01-10
    • 2022-03-07
    相关资源
    最近更新 更多