我正在构建一个Windows Phone项目,其中包含一些部件。我的程序集文件处于ARM模式(CODE32
),它尝试跳转到我知道编译为Thumb的C函数。代码如下:
ldr r12, [pFunc]
mov pc, r12
pFunc
dcd My_C_Function
这是奇怪的事情。代码段中pFunc
处的值是函数thunk加一的指针。也就是说,设置第0位,就好像跳转目标是Thumb并且跳转指令意味着是BX。但是thunk显然是ARM! thunk加载函数体的地址加1并对其执行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如何解码命令?答案 0 :(得分:3)
您需要的详细信息在“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;
如果地址(位0)的低位置1,处理器将清除该位,切换到Thumb模式,并跳转到新地址。
此行为适用于ARMv7及更高版本(即适用于所有Windows Phone设备,但不适用于所有Android / iOS设备)。
答案 1 :(得分:2)
你手上可能有一个有效/真实的问题。 Afaik Windows Phone环境为required to be Thumb-2 only,因此您使用的链接器可能无法处理对ARM模式的调用。在混合程序集和C时,请参阅相同的链接以了解一些注意事项。
如果这是一个Linux / ELF问题,我会以不同的方式回答;
pFunc下的地址由链接器生成,因为它是跨模块调用。所以低位由链接器放在那里。
pFunc
由compiler
生成,linker
将在您构建可加载映像时修复它,该映像已经完全解析为静态重新调用调用。所有可移植对象文件都应该包含一个关于函数模式的表,以便以后链接器可以处理它们并相应地重新定位和更新调用序列。
有关如何通过ELF
文件完成此操作,请参阅ELF for the ARM Architecture - 4.6 Relocation。
答案 2 :(得分:2)
反汇编程序(特别是IDA Demo)通过将几个命令合并为一行来误导我。它从mov
序列中产生了一条mov-orr-orr
行,用于为寄存器分配一个完整的32位常量。毕竟雷通是拇指。链接器按设计工作。
IDA非常棒。我在脑海中知道关于ARM的这种特殊行为,但这一次它滑落了。
我对那些试图提供帮助的人表示不满,感谢和赞成。