[arm64]2、函数调用

1、栈

栈:是一种具有特殊的访问方式的存储空间(后进先出, Last In Out Firt,LIFO)

1.1、SP和FP寄存器

sp寄存器在任意时刻会保存我们栈顶的地址.
fp寄存器也称为x29寄存器属于通用寄存器,但是在某些时刻我们利用它保存栈底的地址!

注意:ARM64开始,取消32位的 LDM,STM,PUSH,POP指令! 取而代之的是ldr\ldp str\stp
ARM64里面 对栈的操作是16字节对齐的!!

1.2、函数调用栈

常见的函数调用开辟和恢复的栈空间

sub    sp, sp, #0x40             ; 拉伸0x40(64字节)空间
stp    x29, x30, [sp, #0x30]     ;x29\x30 寄存器入栈保护
add    x29, sp, #0x30            ; x29指向栈帧的底部
... 
ldp    x29, x30, [sp, #0x30]     ;恢复x29/x30 寄存器的值
add    sp, sp, #0x40             ; 栈平衡
ret
栈空间图

1.3、关于内存读写指令

注意:读/写 数据是都是往高地址读/写

1、str(store register)指令
将数据从寄存器中读出来,存到内存中.
2、ldr(load register)指令
将数据从内存中读出来,存到寄存器中
此ldr 和 str 的变种ldp 和 stp 还可以操作2个寄存器.

1.4、bl和ret指令

1、bl标号

  • 将下一条指令的地址放入lr(x30)寄存器
  • 转到标号处执行指令

2、ret
默认使用lr(x30)寄存器的值,通过底层指令提示CPU此处作为下条指令地址!

ARM64平台的特色指令,它面向硬件做了优化处理的

3、x30寄存器
x30寄存器存放的是函数的返回地址.当ret指令执行时刻,会寻找x30寄存器保存的地址值!

注意:在函数嵌套调用的时候.需要讲x30入栈!

2、函数的参数和返回值

ARM64下,函数的参数是存放在X0到X7(W0到W7)这8个寄存器里面的.如果超过8个参数,就会入栈.
函数的返回值是放在X0 寄存器里面的.

因此函数的参数最好不要超过8个

2.1、实现test函数超过8个参数调用
int test(int a,int b,int c,int d,int e,int f,int g,int h,int i){
    return a+b+c+d+e+f+g+h+i;
}
- (void)viewDidLoad {
    [super viewDidLoad];
    test(1, 2, 3, 4, 5, 6, 7, 8, 9);
}

ViewDidLoad汇编实现

001--Demo`-[ViewController viewDidLoad]:
// 拉伸栈空间
    0x10400a3a0 <+0>:   sub    sp, sp, #0x40             ; =0x40 
    0x10400a3a4 <+4>:   stp    x29, x30, [sp, #0x30]
    0x10400a3a8 <+8>:   add    x29, sp, #0x30            ; =0x30 
    0x10400a3ac <+12>:  stur   x0, [x29, #-0x8]
    0x10400a3b0 <+16>:  stur   x1, [x29, #-0x10]
    0x10400a3b4 <+20>:  ldur   x8, [x29, #-0x8]
    0x10400a3b8 <+24>:  add    x0, sp, #0x10             ; =0x10 
    0x10400a3bc <+28>:  str    x8, [sp, #0x10]
    0x10400a3c0 <+32>:  adrp   x8, 6
    0x10400a3c4 <+36>:  ldr    x8, [x8, #0xc58]
    0x10400a3c8 <+40>:  str    x8, [sp, #0x18]
    0x10400a3cc <+44>:  adrp   x8, 6
    0x10400a3d0 <+48>:  ldr    x1, [x8, #0xc40]
    0x10400a3d4 <+52>:  bl     0x10400a7c4               ; symbol stub for: objc_msgSendSuper2
    0x10400a3d8 <+56>:  mov    w0, #0x1
    0x10400a3dc <+60>:  mov    w1, #0x2
    0x10400a3e0 <+64>:  mov    w2, #0x3
    0x10400a3e4 <+68>:  mov    w3, #0x4
    0x10400a3e8 <+72>:  mov    w4, #0x5
    0x10400a3ec <+76>:  mov    w5, #0x6
    0x10400a3f0 <+80>:  mov    w6, #0x7
    0x10400a3f4 <+84>:  mov    w7, #0x8
->  0x10400a3f8 <+88>:  mov    x9, sp
    0x10400a3fc <+92>:  mov    w8, #0x9
  // 将W8的值保存在上一个栈空间中
    0x10400a400 <+96>:  str    w8, [x9]
    0x10400a404 <+100>: bl     0x10400a328               ; test at ViewController.m:17
    0x10400a408 <+104>: ldp    x29, x30, [sp, #0x30]
    0x10400a40c <+108>: add    sp, sp, #0x40             ; =0x40 
    0x10400a410 <+112>: ret  
viewDidLoad函数执行图

test函数的执行

001--Demo`test:
    0x10400a328 <+0>:   sub    sp, sp, #0x30             ; =0x30 
// 从上一个栈空间从内存读参数到寄存器
->  0x10400a32c <+4>:   ldr    w8, [sp, #0x30]
    0x10400a330 <+8>:   str    w0, [sp, #0x2c]
    0x10400a334 <+12>:  str    w1, [sp, #0x28]
    0x10400a338 <+16>:  str    w2, [sp, #0x24]
    0x10400a33c <+20>:  str    w3, [sp, #0x20]
    0x10400a340 <+24>:  str    w4, [sp, #0x1c]
    0x10400a344 <+28>:  str    w5, [sp, #0x18]
    0x10400a348 <+32>:  str    w6, [sp, #0x14]
    0x10400a34c <+36>:  str    w7, [sp, #0x10]
    0x10400a350 <+40>:  str    w8, [sp, #0xc]
    0x10400a354 <+44>:  ldr    w8, [sp, #0x2c]
    0x10400a358 <+48>:  ldr    w9, [sp, #0x28]
    0x10400a35c <+52>:  add    w8, w8, w9
    0x10400a360 <+56>:  ldr    w9, [sp, #0x24]
    0x10400a364 <+60>:  add    w8, w8, w9
    0x10400a368 <+64>:  ldr    w9, [sp, #0x20]
    0x10400a36c <+68>:  add    w8, w8, w9
    0x10400a370 <+72>:  ldr    w9, [sp, #0x1c]
    0x10400a374 <+76>:  add    w8, w8, w9
    0x10400a378 <+80>:  ldr    w9, [sp, #0x18]
    0x10400a37c <+84>:  add    w8, w8, w9
    0x10400a380 <+88>:  ldr    w9, [sp, #0x14]
    0x10400a384 <+92>:  add    w8, w8, w9
    0x10400a388 <+96>:  ldr    w9, [sp, #0x10]
    0x10400a38c <+100>: add    w8, w8, w9
    0x10400a390 <+104>: ldr    w9, [sp, #0xc]
    0x10400a394 <+108>: add    w0, w8, w9
    0x10400a398 <+112>: add    sp, sp, #0x30             ; =0x30 
    0x10400a39c <+116>: ret  
2.2、返回结构体实现栈传递

OC返回结构体

struct str getStr(int a, int b, int c, int d, int e, int f){
    struct str str1;
    str1.a = a;
    str1.b = b;
    str1.c = c;
    str1.d = d;
    str1.e = e;
    str1.f = f;
    return str1;
}

- (void)viewDidLoad {
    [super viewDidLoad];
    getStr(1, 2, 3, 4, 5, 6);
}

viewDidLoad汇编实现

001--Demo`-[ViewController viewDidLoad]:
    0x104e2e3e4 <+0>:  sub    sp, sp, #0x50             ; =0x50 
    0x104e2e3e8 <+4>:  stp    x29, x30, [sp, #0x40]
    0x104e2e3ec <+8>:  add    x29, sp, #0x40            ; =0x40 
    0x104e2e3f0 <+12>: stur   x0, [x29, #-0x8]
    0x104e2e3f4 <+16>: stur   x1, [x29, #-0x10]
    0x104e2e3f8 <+20>: ldur   x8, [x29, #-0x8]
    0x104e2e3fc <+24>: add    x0, sp, #0x20             ; =0x20 
    0x104e2e400 <+28>: str    x8, [sp, #0x20]
    0x104e2e404 <+32>: adrp   x8, 6
    0x104e2e408 <+36>: ldr    x8, [x8, #0xc58]
    0x104e2e40c <+40>: str    x8, [sp, #0x28]
    0x104e2e410 <+44>: adrp   x8, 6
    0x104e2e414 <+48>: ldr    x1, [x8, #0xc40]
    0x104e2e418 <+52>: bl     0x104e2e7c4               ; symbol stub for: objc_msgSendSuper2
// sp栈顶指针向下偏移8个字节,指针赋值给x8寄存器
    0x104e2e41c <+56>: add    x8, sp, #0x8              ; =0x8 
// 参数赋值给 w0~w5
    0x104e2e420 <+60>: mov    w0, #0x1
    0x104e2e424 <+64>: mov    w1, #0x2
    0x104e2e428 <+68>: mov    w2, #0x3
    0x104e2e42c <+72>: mov    w3, #0x4
    0x104e2e430 <+76>: mov    w4, #0x5
    0x104e2e434 <+80>: mov    w5, #0x6
->  0x104e2e438 <+84>: bl     0x104e2e38c               ; getStr at ViewController.m:30
    0x104e2e43c <+88>: ldp    x29, x30, [sp, #0x40]
    0x104e2e440 <+92>: add    sp, sp, #0x50             ; =0x50 
    0x104e2e444 <+96>: ret    

getStr汇编实现

001--Demo`getStr:
    0x100426594 <+0>:  sub    sp, sp, #0x20             ; =0x20 
    0x100426598 <+4>:  mov    x9, x8
    0x10042659c <+8>:  str    w0, [sp, #0x1c]
    0x1004265a0 <+12>: str    w1, [sp, #0x18]
->  0x1004265a4 <+16>: str    w2, [sp, #0x14]
    0x1004265a8 <+20>: str    w3, [sp, #0x10]
    0x1004265ac <+24>: str    w4, [sp, #0xc]
    0x1004265b0 <+28>: str    w5, [sp, #0x8]
    0x1004265b4 <+32>: ldr    w8, [sp, #0x1c]
    0x1004265b8 <+36>: str    w8, [x9]
    0x1004265bc <+40>: ldr    w8, [sp, #0x18]
    0x1004265c0 <+44>: str    w8, [x9, #0x4]
    0x1004265c4 <+48>: ldr    w8, [sp, #0x14]
    0x1004265c8 <+52>: str    w8, [x9, #0x8]
    0x1004265cc <+56>: ldr    w8, [sp, #0x10]
    0x1004265d0 <+60>: str    w8, [x9, #0xc]
    0x1004265d4 <+64>: ldr    w8, [sp, #0xc]
    0x1004265d8 <+68>: str    w8, [x9, #0x10]
    0x1004265dc <+72>: ldr    w8, [sp, #0x8]
    0x1004265e0 <+76>: str    w8, [x9, #0x14]
    0x1004265e4 <+80>: add    sp, sp, #0x20             ; =0x20 
    0x1004265e8 <+84>: ret    
getStr函数执行过程
2.3、汇编实现a + b的函数
.text
.global _funcA, _sum

_funcA:
    stp x29, x30, [sp, #-0x10]!
    // sub sp, sp, #0x10
    // stp x29, x30, [sp]
    bl _sum
    // ldp x29, x30, [sp]
    // add sp, sp, #0x10
    ldp x29, x30, [sp], #0x10
    ret

_sum:
    add x0, x0, x1
    ret

3、函数的局部变量

函数的局部变量放在栈里面!

3.1、局部变量传递

局部变量c

int funcB(int a, int b) {
    int c = 6;
    return a + b + c;
}

int main(int argc, char * argv[]) {
    funcB(10, 20);
}

funcB的汇编调用

001--Demo`funcB:
->  0x104b4e428 <+0>:  sub    sp, sp, #0x10             ; =0x10 
    0x104b4e42c <+4>:  str    w0, [sp, #0xc]
    0x104b4e430 <+8>:  str    w1, [sp, #0x8]
// 局部变量c
    0x104b4e434 <+12>: mov    w8, #0x6
// 将 c的值写入到内存中,入栈
    0x104b4e438 <+16>: str    w8, [sp, #0x4]
    0x104b4e43c <+20>: ldr    w8, [sp, #0xc]
    0x104b4e440 <+24>: ldr    w9, [sp, #0x8]
    0x104b4e444 <+28>: add    w8, w8, w9
    0x104b4e448 <+32>: ldr    w9, [sp, #0x4]
    0x104b4e44c <+36>: add    w0, w8, w9
    0x104b4e450 <+40>: add    sp, sp, #0x10             ; =0x10 
    0x104b4e454 <+44>: ret    

4、函数的嵌套调用

函数嵌套

int funcB(int a, int b) {
    int c = 6;
    int d = funcSum(a, b, c);
    int e = funcSum(a, b, c);
    return e;
}

int funcSum(int a, int b, int c) {
    int d = a + b + c;
    printf("%d", d);
    return d;
}

int main(int argc, char * argv[]) {
    funcB(10, 20);
}

funcB的汇编

001--Demo`funcB:
    0x100766398 <+0>:  sub    sp, sp, #0x30             ; =0x30 
    0x10076639c <+4>:  stp    x29, x30, [sp, #0x20]
    0x1007663a0 <+8>:  add    x29, sp, #0x20            ; =0x20 
    0x1007663a4 <+12>: stur   w0, [x29, #-0x4]
    0x1007663a8 <+16>: stur   w1, [x29, #-0x8]
    0x1007663ac <+20>: mov    w8, #0x6
    0x1007663b0 <+24>: stur   w8, [x29, #-0xc]
    0x1007663b4 <+28>: ldur   w0, [x29, #-0x4]
    0x1007663b8 <+32>: ldur   w1, [x29, #-0x8]
    0x1007663bc <+36>: ldur   w2, [x29, #-0xc]
    0x1007663c0 <+40>: bl     0x1007663ec               ; funcSum at main.m:28
    0x1007663c4 <+44>: str    w0, [sp, #0x10]
    0x1007663c8 <+48>: ldur   w0, [x29, #-0x4]
    0x1007663cc <+52>: ldur   w1, [x29, #-0x8]
    0x1007663d0 <+56>: ldur   w2, [x29, #-0xc]
    0x1007663d4 <+60>: bl     0x1007663ec               ; funcSum at main.m:28
->  0x1007663d8 <+64>: str    w0, [sp, #0xc]
    0x1007663dc <+68>: ldr    w0, [sp, #0xc]
    0x1007663e0 <+72>: ldp    x29, x30, [sp, #0x20]
    0x1007663e4 <+76>: add    sp, sp, #0x30             ; =0x30 
    0x1007663e8 <+80>: ret    

5、全局变量和常量

全局变量和常量的取值
当前的偏移页数+当前页号+偏移量
adrp x0, 2
add x0, x0, #0xe27

// 全局变量g
int g = 12;
int func(int a, int b) {
    printf("haha"); // 常量 haha
    int c = a + g;
    return c;
}

int main(int argc, char * argv[]) {
    func(1, 2);
    return 0;
}

func的汇编

002-Demo`func:
 0x100d71fd0 <+0>:  sub    sp, sp, #0x20             ; =0x20 
    0x100d71fd4 <+4>:  stp    x29, x30, [sp, #0x10]
    0x100d71fd8 <+8>:  add    x29, sp, #0x10            ; =0x10 
    0x100d71fdc <+12>: stur   w0, [x29, #-0x4]
    0x100d71fe0 <+16>: str    w1, [sp, #0x8]
// 2>>12 + 0x100d71000 + 0xe27
// 2(当前的偏移页数)向右偏移12位 + 0x100d71000(当前页号)+ 0xe27(偏移量)
    0x100d71fe4 <+20>: adrp   x0, 2
    0x100d71fe8 <+24>: add    x0, x0, #0xe27            ; =0xe27 
    0x100d71fec <+28>: bl     0x100d7234c               ; symbol stub for: printf
    0x100d71ff0 <+32>: ldur   w8, [x29, #-0x4]
    0x100d71ff4 <+36>: adrp   x9, 8
    0x100d71ff8 <+40>: ldr    w9, [x9, #0x4a0]
    0x100d71ffc <+44>: add    w8, w8, w9
    0x100d72000 <+48>: str    w8, [sp, #0x4]
    0x100d72004 <+52>: ldr    w0, [sp, #0x4]
    0x100d72008 <+56>: ldp    x29, x30, [sp, #0x10]
    0x100d7200c <+60>: add    sp, sp, #0x20             ; =0x20 
    0x100d72010 <+64>: ret    
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,056评论 5 474
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,842评论 2 378
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 148,938评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,296评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,292评论 5 363
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,413评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,824评论 3 393
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,493评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,686评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,502评论 2 318
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,553评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,281评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,820评论 3 305
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,873评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,109评论 1 258
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,699评论 2 348
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,257评论 2 341

推荐阅读更多精彩内容