试图了解iOS应用程序的ARM程序集

时间:2014-12-02 10:01:33

标签: objective-c assembly arm

考虑以下Objective C接口定义

#import <Foundation/Foundation.h>

@interface MyClass : NSObject

  @property NSObject* myprop;

@end

Xcode 5为[MyClass myprop]为ARMv7生成的程序集看起来像

    .code   16                      @ @"\01-[MyClass myprop]"
    .thumb_func "-[MyClass myprop]"
"-[MyClass myprop]":
Lfunc_begin0:
    .cfi_startproc
@ BB#0:
    sub sp, #8
    @DEBUG_VALUE: -[MyClass myprop]:self <- undef
    @DEBUG_VALUE: -[MyClass myprop]:_cmd <- undef
    str r0, [sp, #4]
    str r1, [sp]
    ldr r0, [sp, #4]
    movw    r2, :lower16:(_OBJC_IVAR_$_MyClass.myprop-(LPC0_0+4))
    movt    r2, :upper16:(_OBJC_IVAR_$_MyClass.myprop-(LPC0_0+4))
LPC0_0:
    add r2, pc
    ldr r2, [r2]
    movs    r3, #1
    add sp, #8
    b.w _objc_getProperty
Ltmp0:
Lfunc_end0:
    .cfi_endproc

我想了解最终的程序集,并对其提出以下问题:

1)最后一条指令(b.w _objc_getProperty)将PC设置为标签_objc_getProperty的地址。但是这个程序怎么知道在哪里跳回来?是否假设使用bl调用该方法,因此链接寄存器包含目标地址?

2)第二个@DEBUG_VALUE下方的3行是做什么的?

如果我理解正确,r0的内容存储在堆栈偏移4处,r1存储在当前堆栈(偏移0),r0填充堆栈偏移4.但为什么最后一条指令会改变什么?它不仅仅意味着r0充满了已经包含的内容吗?用于什么值? _obj_getProperty

3)为什么r3最后设置为1? (movs r3, #1)?

1 个答案:

答案 0 :(得分:1)

在C代码中,函数可能如下所示:

resulttype Lfunc_begin0(type1 arg1, type2 arg2)
{
    return _objc_getProperty(arg1, arg2, Myclass_myprop, 1);
}

首先让我们看看下面的例子:

int func(void)
{
    a();
    b();
    return c();
}

现在可以通过以下方式对“c()”进行函数调用:

save_lr
bl a
bl b
bl c
restore_original_lr
bx lr

或者可以执行以下代码:

save_lr
bl a
bl b
restore_original_lr
b c

在这种情况下,“c()”末尾的“bx lr”指令将直接跳转到调用自己的函数,我们不必执行“bx lr”。

因为C代码中的某些函数调用可能会破坏R0和R1的内容,所以未经优化的C代码会将这些寄存器保存到堆栈中,只是为了稍后需要它们的值。经过优化的C代码会检查这个并删除“@DEBUG”行之后的三条指令。甚至“添加SP”和“子SP”线也可以优化掉!

_obj_getProperty函数显然需要四个参数。简单地传递R0和R1(如上面的C代码所示),而R2和R3是该函数的附加参数。

从这里显示的汇编程序代码中无法看到第4个参数(R3 = 1)的真正意义。