Objective-C 函数参数汇编分析

环境 Mac OS X 10.7.5,Xcode 4.3.2,64-bit,Debug,lldb
先看三个简单的方法

-(void)print 
{
    NSLog(@"0");
}

-(void)print:(NSString*)s1
{
    NSLog(@"1 %@", s1);
}

-(void)print:(NSString*)s1 s2:(NSString*)s2
{
    NSLog(@"2 %@ %@", s1, s2);
}

-(void)print:(NSString*)s1 s2:(NSString*)s2 s3:(NSString*)s3
{
    NSLog(@"3 %@ %@ %@", s1, s2, s3);
}

在函数入口点下断点,lldb输入dis -fm查看对应的反汇编

15      -(void)print 
16      {
0x10fbfc1a0:  pushq  %rbp
0x10fbfc1a1:  movq   %rsp, %rbp
0x10fbfc1a4:  subq   $16, %rsp
0x10fbfc1a8:  leaq   13681(%rip), %rax        ; 0x000000010fbff720 @"'0'"
0x10fbfc1af:  movq   %rdi, -8(%rbp)
0x10fbfc1b3:  movq   %rsi, -16(%rbp)
testm`-[BaseTest print] + 23 at BaseTest.m:17
16      {
-> 17       NSLog(@"0");
18      }
-> 0x10fbfc1b7:  movq   %rax, %rdi
0x10fbfc1ba:  movb   $0, %al
0x10fbfc1bc:  callq  0x000000010fbfc88e       ; NSLog
testm`-[BaseTest print] + 33 at BaseTest.m:18
17          NSLog(@"0");
18      }
19      
0x10fbfc1c1:  addq   $16, %rsp
0x10fbfc1c5:  popq   %rbp
0x10fbfc1c6:  ret

虽然没有参数,但是我们看到:最后出栈时,rsp还是增加了16字节,相当于两个指针参数。究其原因,调用Objective-C的方法其实是给对象发消息,最底层都是由objc_mesgSend完成。objc_msgSend大致是下面这样:

IMP class_getMethodImplementation(Class cls, SEL name);

id objc_msgSend(id receiver, SEL name, arguments...) {
    IMP function = class_getMethodImplementation(receiver->isa, name);
    return function(receiver, name, arguments); 
}

[self print]等于 objc_msgSend(self, @selector(print:)); // ps:准确说,第一个参数不是self)

据实际观察,-16(%rbp)是SEL参数"print:",-8(%rbp)是self对象的地址。又由于它们分别从rdi和rsi得来。所以,objc_msgSend的这两个标准参数是存放在rdi和rsi寄存器中的。

下面看看1个参数的反汇编

20      -(void)print1:(NSString*)s1
21      {
0x10fbfc1d0:  pushq  %rbp
0x10fbfc1d1:  movq   %rsp, %rbp
0x10fbfc1d4:  subq   $32, %rsp
0x10fbfc1d8:  leaq   13665(%rip), %rax        ; 0x000000010fbff740 @"1 %@"
0x10fbfc1df:  movq   %rdi, -8(%rbp)
0x10fbfc1e3:  movq   %rsi, -16(%rbp)
0x10fbfc1e7:  movq   %rdx, -24(%rbp)
testm`-[BaseTest print1:] + 27 at BaseTest.m:22
21      {
-> 22       NSLog(@"1 %@", s1);
23      }
-> 0x10fbfc1eb:  movq   -24(%rbp), %rsi
0x10fbfc1ef:  movq   %rax, %rdi
0x10fbfc1f2:  movb   $0, %al
0x10fbfc1f4:  callq  0x000000010fbfc88e       ; NSLog
testm`-[BaseTest print1:] + 41 at BaseTest.m:23
22          NSLog(@"1 %@", s1);
23      }
24      
0x10fbfc1f9:  addq   $32, %rsp
0x10fbfc1fd:  popq   %rbp
0x10fbfc1fe:  ret    
0x10fbfc1ff:  nop

很显然,参数s1是位于rdx并保持在栈-24(%rbp)处。 但是这次出栈有32字节,相比上一次都了16字节。说明栈有4个局部变量,可是我们没看到-32(%rbp)在任何地方使用。先猜测是用于堆栈检查,因为windows经常这么干。

再看看2个参数的情况

33      -(void)print2:(NSString*)s1 s2:(NSString*)s2
34      {
0x10d12c1c0:  pushq  %rbp
0x10d12c1c1:  movq   %rsp, %rbp
0x10d12c1c4:  subq   $32, %rsp
0x10d12c1c8:  leaq   13665(%rip), %rax        ; 0x000000010d12f730 @"2 %@ %@"
0x10d12c1cf:  movq   %rdi, -8(%rbp)
0x10d12c1d3:  movq   %rsi, -16(%rbp)
0x10d12c1d7:  movq   %rdx, -24(%rbp)
0x10d12c1db:  movq   %rcx, -32(%rbp)
testm`-[BaseTest print2:s2:] + 31 at BaseTest.m:35
34      {
-> 35       NSLog(@"2 %@ %@", s1, s2);
36      }
-> 0x10d12c1df:  movq   -24(%rbp), %rsi
0x10d12c1e3:  movq   -32(%rbp), %rdx
0x10d12c1e7:  movq   %rax, %rdi
0x10d12c1ea:  movb   $0, %al
0x10d12c1ec:  callq  0x000000010d12c854       ; NSLog
testm`-[BaseTest print2:s2:] + 49 at BaseTest.m:36
35          NSLog(@"2 %@ %@", s1, s2);
36      }
37      
0x10d12c1f1:  addq   $32, %rsp
0x10d12c1f5:  popq   %rbp
0x10d12c1f6:  ret

第二个参数s2位于%rcx中,但是rsp出栈仍然是32,说明不太可能是栈检查。我们看看三个参数有没有不同

38      -(void)print3:(NSString*)s1 s2:(NSString*)s2 s3:(NSString*)s3
39      {
0x1091f5200:  pushq  %rbp
0x1091f5201:  movq   %rsp, %rbp
0x1091f5204:  subq   $48, %rsp
0x1091f5208:  leaq   13633(%rip), %rax        ; 0x00000001091f8750 @"3 %@ %@ %@"
0x1091f520f:  movq   %rdi, -8(%rbp)
0x1091f5213:  movq   %rsi, -16(%rbp)
0x1091f5217:  movq   %rdx, -24(%rbp)
0x1091f521b:  movq   %rcx, -32(%rbp)
0x1091f521f:  movq   %r8, -40(%rbp)
testm`-[BaseTest print3:s2:s3:] + 35 at BaseTest.m:40
39      {
-> 40       NSLog(@"3 %@ %@ %@", s1, s2, s3);
41      }
-> 0x1091f5223:  movq   -24(%rbp), %rsi
0x1091f5227:  movq   -32(%rbp), %rdx
0x1091f522b:  movq   -40(%rbp), %rcx
0x1091f522f:  movq   %rax, %rdi
0x1091f5232:  movb   $0, %al
0x1091f5234:  callq  0x00000001091f5854       ; NSLog
testm`-[BaseTest print3:s2:s3:] + 57 at BaseTest.m:41
40          NSLog(@"3 %@ %@ %@", s1, s2, s3);
41      }
42      @end
0x1091f5239:  addq   $48, %rsp
0x1091f523d:  popq   %rbp
0x1091f523e:  ret

这次无一例外,参数还是通过寄存器传递。这次常用寄存器不够,就放在%r8。iMac的General Purpose Register有r8~r15,通常我们根本用不完。 最后出栈变成了48而不是40,从这个规律可以发现,rsp的增长都是以偶数个寄存器长度。读者有兴趣试一试4、5个参数。

另外,像NSLog这种可变参数的C api没有遵循__cdecl那种调用方清栈的规则,也是通过寄存器,以movb $0, %al作为结尾,通过其他方式计算个数。


转自我的博客http://blog.csdn.net/ani_di/article/details/8954572

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,123评论 6 490
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,031评论 2 384
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 156,723评论 0 345
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,357评论 1 283
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,412评论 5 384
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,760评论 1 289
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,904评论 3 405
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,672评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,118评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,456评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,599评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,264评论 4 328
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,857评论 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,731评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,956评论 1 264
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,286评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,465评论 2 348

推荐阅读更多精彩内容