我的iOS应用程序使用Apple LLVM 3.0编译器以Thumb模式构建。对于armv7,我非常确定实际上是Thumb-2。
我正在用ARM汇编代码重新实现我最耗时的两个函数。这些函数的调用方是Thumb,因此我在函数序言中使用Thumb到ARM互操作指令切换到ARM,以便可以访问ARM更丰富的指令集和更多的寄存器。在函数退出时,我使用ARM到Thumb的互操作返回到ARM模式。
GDB的反汇编对于Thumb代码是正确的,但是当我处于ARM模式时,它会将ARM指令解析为一对完全无意义的Thumb指令。有没有办法告诉GDB切换到ARM反汇编,然后返回到Thumb代码时使用Thumb反汇编器?
Google没有帮助。显然还有其他的GDB分支可以做到这一点,但是我还没有找到在GDB中执行此操作的方法。
LLDB显然支持ARM调试,但是在Xcode 4.2中尚不能在iOS设备上运行。当我选择LLDB调试器并在我的代码中设置断点时,我的应用程序在达到断点之前就挂起了。
我很久没有做过任何类型的汇编语言了,所以我正在通过在C和ARM汇编中实现具有不同参数和返回不同类型结果的函数来学习ARM调用约定。lower_case函数是C,CamelCase函数是汇编。我从main()非常第一件事就调用了abiTest,并使用assert()确保它返回YES。
si指令始终做正确的事情,无论我们处于Thumb模式还是ARM模式,它只会推进一条指令。因此,GDB必须知道当前的指令集架构,只是反汇编程序没有获取到这些信息。在ARM寄存器中有一个位指示当前模式。一些GDB分支可以使用该位的值确定要反汇编的ISA,但Xcode 4.2的GDB显然不支持此功能。 Xcode的GDB具有“set arm disassembler”命令及其相应的“show arm disassembler”,看起来似乎有所帮助,但实际并非如此。这项功能显然是为支持iOS设备未使用的其他类型的ARM变体而设计的。在其他GDB分支中,“set fallback-mode”可以设置为arm、thumb或auto,但在Xcodes中不能,同样的情况也适用于“set disassembler-flavor”。我真正想要的是一款机器调试器,它像Classic Mac OS上的MacsBug一样工作。虽然GDB通常能够进行汇编程序调试,但对于这个目的来说,它完全不太好用。这并不是任何人的过错,因为它是为源代码调试而设计的。一个好的汇编程序调试器从底层就是这样设计的。
我正在用ARM汇编代码重新实现我最耗时的两个函数。这些函数的调用方是Thumb,因此我在函数序言中使用Thumb到ARM互操作指令切换到ARM,以便可以访问ARM更丰富的指令集和更多的寄存器。在函数退出时,我使用ARM到Thumb的互操作返回到ARM模式。
GDB的反汇编对于Thumb代码是正确的,但是当我处于ARM模式时,它会将ARM指令解析为一对完全无意义的Thumb指令。有没有办法告诉GDB切换到ARM反汇编,然后返回到Thumb代码时使用Thumb反汇编器?
Google没有帮助。显然还有其他的GDB分支可以做到这一点,但是我还没有找到在GDB中执行此操作的方法。
LLDB显然支持ARM调试,但是在Xcode 4.2中尚不能在iOS设备上运行。当我选择LLDB调试器并在我的代码中设置断点时,我的应用程序在达到断点之前就挂起了。
我很久没有做过任何类型的汇编语言了,所以我正在通过在C和ARM汇编中实现具有不同参数和返回不同类型结果的函数来学习ARM调用约定。lower_case函数是C,CamelCase函数是汇编。我从main()非常第一件事就调用了abiTest,并使用assert()确保它返回YES。
BOOL abiTest( void )
{
void_no_args();
VoidNoArgs();
if ( 42 != int_no_args() )
return NO;
if ( 42 != IntNoArgs() )
return NO;
return YES;
}
这里是IntNoArgs的源代码。.thumb_func是链接器的指令。我的研究表明,即使在混合两种类型的代码时,如果一个人同时使用ARM函数,也需要它。
.globl _IntNoArgs
.align 1
.code 16
.thumb_func _IntNoArgs
_IntNoArgs:
@ int IntNoArgs( void );
.loc 1 __LINE__ 0
adr r0, Larm1 @ Larm1 is a PC-relative address. r0's low bit will be cleared
bx r0 @ Switch to ARM mode then branch to Larm1. That's the next instruction
.align 2
.code 32
Larm1:
stmfd sp!, { r7, lr }
mov r0, #42
ldmfd sp!, { r7, lr }
bx lr
以下是 GDB 如何反汇编 _IntNoArgs。前两行是正确的,其余完全错误。
0x000172c8 <+0000> add r0, pc, #0 (adr r0, 0x172cc <VoidNoArgs+4>)
0x000172ca <+0002> bx r0
0x000172cc <+0004> lsls r0, r0
0x000172ce <+0006> stmdb sp!, {r1, r3, r5}
0x000172d2 <+0010> b.n 0x17a16
0x000172d4 <+0012> lsls r0, r0
0x000172d6 <+0014> ldmia.w sp!, {r1, r2, r3, r4, r8, r9, r10, r11, r12, sp, lr, pc}
因为ldmia.w指令从堆栈中取出一个新值并将其放入程序计数器中,从而返回子例程,所以反汇编在此处停止。使用"si"单步执行该指令后,反汇编面板显示如下:
0x000172d8 <+0016> vrhadd.u16 d14, d14, d31
si指令始终做正确的事情,无论我们处于Thumb模式还是ARM模式,它只会推进一条指令。因此,GDB必须知道当前的指令集架构,只是反汇编程序没有获取到这些信息。在ARM寄存器中有一个位指示当前模式。一些GDB分支可以使用该位的值确定要反汇编的ISA,但Xcode 4.2的GDB显然不支持此功能。 Xcode的GDB具有“set arm disassembler”命令及其相应的“show arm disassembler”,看起来似乎有所帮助,但实际并非如此。这项功能显然是为支持iOS设备未使用的其他类型的ARM变体而设计的。在其他GDB分支中,“set fallback-mode”可以设置为arm、thumb或auto,但在Xcodes中不能,同样的情况也适用于“set disassembler-flavor”。我真正想要的是一款机器调试器,它像Classic Mac OS上的MacsBug一样工作。虽然GDB通常能够进行汇编程序调试,但对于这个目的来说,它完全不太好用。这并不是任何人的过错,因为它是为源代码调试而设计的。一个好的汇编程序调试器从底层就是这样设计的。