Peeking Stack Frame

为了更加清晰的了解stack frame 是什么,下面写了测试的代码并附上debug信息 。可能比较冗长,耐心查看必有收获!

- (void)viewDidLoad {
    [super viewDidLoad];
    [self launchUCBrowser];
}
- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}
- (void)launchUCBrowser
{
    [self clickSearchBar];
}
- (void)clickSearchBar
{
    [self typing];
}
- (void)typing
{
    NSLog(@"Hello world");
}

首先查看一下当前程序加载到内存的起始地址:

(lldb) image list
[  0] B8DF937E-E66C-3633-AEE8-87CFE8EA18DE 0x00000001000d8000 /Users/vedon/Library/Developer/Xcode/DerivedData/StackFrame-blkbdwapfezplhfqiynvukzdvxgc/Build/Products/Debug-iphoneos/StackFrame.app/StackFrame 

分别在每个函数执行的位置打上断点,并把当前的寄存器的值打印出来。以下去除了部分数据的寄存器数据:

(lldb) register read
General Purpose Registers:
        x0 = 0x0000000109d0aab0
        x1 = 0x000000018b331732  "viewDidLoad"
        x2 = 0x0000000000000001
        fp = 0x000000016fd25f70
        lr = 0x00000001000de710  StackFrame`-[ViewController viewDidLoad] + 68 at ViewController.m:17
        sp = 0x000000016fd25f50
        pc = 0x00000001000de718  StackFrame`-[ViewController viewDidLoad] + 76 at ViewController.m:18
(lldb) register read
General Purpose Registers:
        x0 = 0x0000000109d0aab0
        x1 = 0x00000001000dec90  "launchUCBrowser"
        x2 = 0x0000000000000001
        fp = 0x000000016fd25f40
        lr = 0x00000001000de728  StackFrame`-[ViewController viewDidLoad] + 92 at ViewController.m:19
        sp = 0x000000016fd25f30
        pc = 0x00000001000de7a0  StackFrame`-[ViewController launchUCBrowser] + 28 at ViewController.m:31
(lldb) register read
General Purpose Registers:
        x0 = 0x0000000109d0aab0
        x1 = 0x00000001000decb8  "clickSearchBar"
        x2 = 0x0000000000000001
        fp = 0x000000016fd25f20
        lr = 0x00000001000de7ac  StackFrame`-[ViewController launchUCBrowser] + 40 at ViewController.m:32
        sp = 0x000000016fd25f10
        pc = 0x00000001000de7d4  StackFrame`-[ViewController clickSearchBar] + 28 at ViewController.m:36
(lldb) register read
General Purpose Registers:
        x0 = 0x0000000109d0aab0
        x1 = 0x00000001000decc7  "typing"
        x2 = 0x0000000000000001
        fp = 0x000000016fd25f00
        lr = 0x00000001000de7e0  StackFrame`-[ViewController clickSearchBar] + 40 at ViewController.m:37
        sp = 0x000000016fd25ef0
        pc = 0x00000001000de800  StackFrame`-[ViewController typing] + 20 at ViewController.m:41

可以看到:

  • x0 的地址都一样,代表的self
  • x1 就是函数的selector
  • lr 保存了方法调用完后,返回的地址。
  • pc 就是当前执行的指令地址。

fp 与 sp 是一个frame 的界限。如下表:

function name fp sp desc
viewDidLoad 0x000000016fd25f70 0x000000016fd25f50 此fp 和sp 构成了上caller的frame
launchUCBrowser 0x000000016fd25f40 0x000000016fd25f30 此fp 和sp 构成了上viewDidLoad的frame
clickSearchBar 0x000000016fd25f20 0x000000016fd25f10 此fp 和sp 构成了上launchUCBrowser的frame
typing 0x000000016fd25f00 0x000000016fd25ef0 此fp 和sp 构成了上clickSearchBar的frame

下面是demo 在hopper 内容:

; ================ B E G I N N I N G   O F   P R O C E D U R E ================


                     -[ViewController viewDidLoad]:
00000001000066cc         sub        sp, sp, #0x30                               ; Objective C Implementation defined at 0x1000080f8 (instance method), DATA XREF=0x1000080f8
// sp = sp - 0x30
00000001000066d0         stp        x29, x30, [sp, #0x20]
//将x29(fp) ,x30(lr) 存入 sp + 0x20。sp = sp + 0x20 (指针下移),注意这里是上一次方法调用存进来的,用于方法调用完之后恢复上一次调用。
00000001000066d4         add        x29, sp, #0x20
//设置当前函数的fp = sp + 0x20
00000001000066d8         mov        x8, sp
//将sp 的值保存到x8
00000001000066dc         adrp       x9, #0x100008000
//把当前pc的值后12bit 设为0,并把0x100008000 << 12,然后把两者相加存入x9.
00000001000066e0         add        x9, x9, #0xcd0                              ; @selector(viewDidLoad)
//x9 = x9 + 0xcd0 定位到viewDidLoad
00000001000066e4         adrp       x10, #0x100008000
//同上
00000001000066e8         add        x10, x10, #0xd08                            ; 0x100008d08
00000001000066ec         stur       x0, [x29, #-0x8]
//把x0 存入 fp - 0x8 
00000001000066f0         str        x1, [sp, #0x10]
// 把x1 存入 sp + 0x10
00000001000066f4         ldur       x0, [x29, #-0x8]
//把存在 fp - 0x8 的内容存入x0 ,这里可以看到和上面的操作是相对的,刚被存到sp + 0x10 ,又马上拿出来。如果编译器允许基本的编译优化,这些多余的指令会被删除。
00000001000066f8         str        x0, sp
//把 x0 存入 sp
00000001000066fc         ldr        x10, x10
0000000100006700         str        x10, [sp, #0x8]
// 把x10 存入 sp + 0x8
0000000100006704         ldr        x1, x9
// 把x9 存入x1 ,x9 就是viewDidload 的地址
0000000100006708         mov        x0, x8
// 把 x8 存入 x0 
000000010000670c         bl         imp___stubs__objc_msgSendSuper2
// 执行 [super viewDidLoad]
0000000100006710         adrp       x8, #0x100008000
// 把当前pc的值后12bit 设为0,并把0x100008000 << 12,然后把两者相加存入x8.
0000000100006714         add        x8, x8, #0xcd8                              ; @selector(launchUCBrowser)
//  x8 = x8 +  0xcd8 ,定位到launchUCBrowser
0000000100006718         ldur       x9, [x29, #-0x8]
// 把x29 - 0x8 存入x9
000000010000671c         ldr        x1, x8
//把x8 存入 x1
0000000100006720         mov        x0, x9
// 把 x9 存入x0 
0000000100006724         bl         imp___stubs__objc_msgSend
0000000100006728         ldp        x29, x30, [sp, #0x20]
//从sp + 0x20 取数据,存入 fp 和sp . (ldp/stp 从栈取/存数据)
000000010000672c         add        sp, sp, #0x30
//sp = sp + 0x30
0000000100006730         ret

                     -[ViewController launchUCBrowser]:
0000000100006784         sub        sp, sp, #0x20                               ; Objective C Implementation defined at 0x100008128 (instance method), DATA XREF=0x100008128
// sp = sp - 0x20 
0000000100006788         stp        x29, x30, [sp, #0x10]
// 把 fp 和 sp 存入 sp + 0x10 ,并且 sp = sp + 0x10
000000010000678c         add        x29, sp, #0x10
// fp = sp + 0x10
0000000100006790         adrp       x8, #0x100008000
//把当前pc的值后12bit 设为0,并把0x100008000 << 12,然后把两者相加存入x8
0000000100006794         add        x8, x8, #0xce8                              ; @selector(clickSearchBar)
//x8 = x8 +  0xcd8 ,定位到launchUCBrowser
0000000100006798         str        x0, [sp, #0x8]
// 把x0 存入 sp + 0x8
000000010000679c         str        x1, sp
// 把 x1 存入 sp
00000001000067a0         ldr        x0, [sp, #0x8]
// 把 sp + 0x8 存入 x0
00000001000067a4         ldr        x1, x8
// 把 x8 存入 x1
00000001000067a8         bl         imp___stubs__objc_msgSend
00000001000067ac         ldp        x29, x30, [sp, #0x10]
//从sp + 0x20 取数据,存入 fp 和sp . (ldp/stp 从栈取/存数据)
00000001000067b0         add        sp, sp, #0x20
00000001000067b4         ret
                        ; endp
        ; ================ B E G I N N I N G   O F   P R O C E D U R E ================


                     -[ViewController clickSearchBar]:
00000001000067b8         sub        sp, sp, #0x20                               ; Objective C Implementation defined at 0x100008140 (instance method), DATA XREF=0x100008140
00000001000067bc         stp        x29, x30, [sp, #0x10]
00000001000067c0         add        x29, sp, #0x10
00000001000067c4         adrp       x8, #0x100008000
00000001000067c8         add        x8, x8, #0xcf0                              ; @selector(typing)
00000001000067cc         str        x0, [sp, #0x8]
00000001000067d0         str        x1, sp
00000001000067d4         ldr        x0, [sp, #0x8]
00000001000067d8         ldr        x1, x8
00000001000067dc         bl         imp___stubs__objc_msgSend
00000001000067e0         ldp        x29, x30, [sp, #0x10]
00000001000067e4         add        sp, sp, #0x20
00000001000067e8         ret
                        ; endp


        ; ================ B E G I N N I N G   O F   P R O C E D U R E ================


                     -[ViewController typing]:
00000001000067ec         sub        sp, sp, #0x20                               ; Objective C Implementation defined at 0x100008158 (instance method), DATA XREF=0x100008158
00000001000067f0         stp        x29, x30, [sp, #0x10]
00000001000067f4         add        x29, sp, #0x10
00000001000067f8         str        x0, [sp, #0x8]
00000001000067fc         str        x1, sp
0000000100006800         adrp       x0, #0x100008000                            ; argument #1 for method imp___stubs__NSLog
0000000100006804         add        x0, x0, #0x60                               ; @"Hello world"
0000000100006808         bl         imp___stubs__NSLog
000000010000680c         ldp        x29, x30, [sp, #0x10]
0000000100006810         add        sp, sp, #0x20
0000000100006814         ret

不知道大家有没有发现,

function name assembly range
viewDidLoad x29, x30, [sp, #0x20] 0x000000016fd25f70 - 0x000000016fd25f50 = 0x20
launchUCBrowser x29, x30, [sp, #0x10] 0x000000016fd25f40 - 0x000000016fd25f30 = 0x10

压栈的范围是有调用函数的frame 决定的。通过fp 和sp ,就可以得出所有函数的调用顺序。

To be continue

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

推荐阅读更多精彩内容