对如何开始了解iOS下的ARM感到好奇。任何帮助都会非常好。
答案 0 :(得分:20)
在我看来,最好的入门方式是
要执行此操作,您可以使用Xcode:
将以下函数添加到scratchpad.c:
void do_nothing(void)
{
return;
}
如果您现在在助理编辑器中刷新程序集,您应该会看到许多以点(指令)开头的行,后跟
_do_nothing:
@ BB#0:
bx lr
让我们暂时忽略这些指令并查看这三行。通过在互联网上进行一些搜索,您会发现这些行是:
b
表示分支,暂时忽略x
(它与指令集之间的切换有关),lr
是链接寄存器,其中调用者存储返回地址。 / LI>
醇>
让我们加强一点并将代码更改为:
extern void do_nothing(void);
void do_nothing_twice(void)
{
do_nothing();
do_nothing();
}
保存并刷新程序集后,您将获得以下代码:
_do_nothing_twice:
@ BB#0:
push {r7, lr}
mov r7, sp
blx _do_nothing
pop.w {r7, lr}
b.w _do_nothing
再次,通过在互联网上进行一些搜索,你会发现每一行的含义。还需要完成一些工作,因为要进行两次调用:第一次调用需要返回给我们,因此我们需要更改lr
。这是由blx
指令完成的,该指令不仅分支到_do_nothing
,还在lr
中存储下一条指令的地址(返回地址)。
因为我们更改了返回地址,所以我们必须将它存储在某个地方,因此它被推送到堆栈中。第二个跳转后缀为.w
,但暂时忽略它。为什么函数看起来不像这样?
_do_nothing_twice:
@ BB#0:
push {lr}
blx _do_nothing
pop.w {lr}
b.w _do_nothing
这也可以,但在iOS中,惯例是将帧指针存储在r7
中。帧指针指向堆栈中我们存储前一帧指针和前一个返回地址的位置。
所以代码的作用是:首先,它将r7
和lr
推送到堆栈,然后将r7
设置为指向新的堆栈帧(位于顶部)堆栈的,并且sp
指向堆栈的顶部),然后它第一次分支,然后它恢复r7
和lr
,最后它第二次分支。最后不需要bx lr
,因为被调用函数将返回lr
,它指向我们的调用者。
让我们看看最后一个例子:
void swap(int *x, int *y)
{
int temp = *x;
*x = *y;
*y = temp;
}
汇编代码是:
_swap:
@ BB#0:
ldr r2, [r0]
ldr r3, [r1]
str r3, [r0]
str r2, [r1]
bx lr
通过一些搜索,您将了解到参数和返回值存储在寄存器r0
- r3
中,并且我们可以自由地使用它们进行计算。代码的作用很简单:它加载r0
和r1
指向r2
和r3
的值,然后将它们以交换顺序存储回来,然后分支回来。
就是这样:写下小片段,获取足够的信息以大致了解每行中发生的事情,重复一遍。希望有所帮助!