考虑以下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
)?
答案 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)的真正意义。