如何在iOS上开始使用ARM?

时间:2012-10-31 19:20:23

标签: objective-c ios c arm

对如何开始了解iOS下的ARM感到好奇。任何帮助都会非常好。

1 个答案:

答案 0 :(得分:20)

在我看来,最好的入门方式是

  1. 编写C代码的小片段(后面的Objective-C)
  2. 查看相应的汇编代码
  3. 找出足以理解汇编代码
  4. 重复!
  5. 要执行此操作,您可以使用Xcode:

    1. 创建一个新的iOS项目(单视图应用程序很好)
    2. 添加C文件scratchpad.c
    3. 在项目构建设置中,将“生成调试符号”设置为“否”
    4. 确保目标是iOS设备,而不是模拟器
    5. 打开scratchpad.c并打开助理编辑器
    6. 将助理编辑器设置为Assembly,然后选择“Release”
    7. 示例1

      将以下函数添加到scratchpad.c:

      void do_nothing(void)
      {
          return;
      }
      

      如果您现在在助理编辑器中刷新程序集,您应该会看到许多以点(指令)开头的行,后跟

      _do_nothing:
      @ BB#0:
          bx  lr
      

      让我们暂时忽略这些指令并查看这三行。通过在互联网上进行一些搜索,您会发现这些行是:

      1. 标签(以下划线为前缀的功能名称)。
      2. 只是编译器发出的评论。
      3. 退货声明。 b表示分支,暂时忽略x(它与指令集之间的切换有关),lr是链接寄存器,其中调用者存储返回地址。 / LI>

        示例2

        让我们加强一点并将代码更改为:

        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中。帧指针指向堆栈中我们存储前一帧指针和前一个返回地址的位置。

        所以代码的作用是:首先,它将r7lr推送到堆栈,然后将r7设置为指向新的堆栈帧(位于顶部)堆栈的,并且sp指向堆栈的顶部),然后它第一次分支,然后它恢复r7lr,最后它第二次分支。最后不需要bx lr,因为被调用函数将返回lr,它指向我们的调用者。

        示例3

        让我们看看最后一个例子:

        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中,并且我们可以自由地使用它们进行计算。代码的作用很简单:它加载r0r1指向r2r3的值,然后将它们以交换顺序存储回来,然后分支回来。

        等等

        就是这样:写下小片段,获取足够的信息以大致了解每行中发生的事情,重复一遍。希望有所帮助!