汇编-----函数的本质

通过汇编代码我们可以探索函数的本质

  • 1: 如果函数内部没有调用其他函数, 那么sp不会进行偏移, 编译器会通过mov bp - N, 0x11的方式向栈中存入数据. 这是编译器所进行的优化.这个时候这个栈中的区域被称为 红色区域 不超过128个字节
    • 如果局部变量超过128个字节, 那么还是需要 sub sp, N来开辟栈空间
  int sum(int a, int b, int c) {
      int x = 10;
     // test();
      return a + b + c + x;
  }
可以看到, 如果函数内部没有调用其他函数, 并且所有参数的总字节数没有超过128个字节时 CPU并不会开辟新的空间,而是使用红色区域去存储变量
safe005`sum:
    0x103d90700 <+0>:  pushq  %rbp
    0x103d90701 <+1>:  movq   %rsp, %rbp
    0x103d90704 <+4>:  movl   %edi, -0x4(%rbp)
    0x103d90707 <+7>:  movl   %esi, -0x8(%rbp)
    0x103d9070a <+10>: movl   %edx, -0xc(%rbp)
->  0x103d9070d <+13>: movl   $0xa, -0x10(%rbp)
    0x103d90714 <+20>: movl   -0x4(%rbp), %edx
    0x103d90717 <+23>: addl   -0x8(%rbp), %edx
    0x103d9071a <+26>: addl   -0xc(%rbp), %edx
    0x103d9071d <+29>: addl   -0x10(%rbp), %edx
    0x103d90720 <+32>: movl   %edx, %eax
    0x103d90722 <+34>: popq   %rbp
    0x103d90723 <+35>: retq   
  • 2: 如果函数内部调用其他函数, 则必会通过 sub sp, N 来开辟栈空间
  void test() {
    
  }

  int sum(int a, int b, int c) {
      int x = 10;
      test();
      return a + b + c + x;
  }
以下是上边函数的汇编代码, 可以看到, 如果函数内部调用了其他函数, 则sp必会上移,开辟栈空间, 这时候 下一条指令的地址在 栈空间上一位, bp在上2位
    0x10417b6f0 <+0>:  pushq  %rbp
    0x10417b6f1 <+1>:  movq   %rsp, %rbp
    0x10417b6f4 <+4>:  subq   $0x10, %rsp
    0x10417b6f8 <+8>:  movl   %edi, -0x4(%rbp)
    0x10417b6fb <+11>: movl   %esi, -0x8(%rbp)
    0x10417b6fe <+14>: movl   %edx, -0xc(%rbp)
->  0x10417b701 <+17>: movl   $0xa, -0x10(%rbp)
    0x10417b708 <+24>: callq  0x10417b6e0               ; test at main.m:12
    0x10417b70d <+29>: movl   -0x4(%rbp), %edx
    0x10417b710 <+32>: addl   -0x8(%rbp), %edx
    0x10417b713 <+35>: addl   -0xc(%rbp), %edx
    0x10417b716 <+38>: addl   -0x10(%rbp), %edx
    0x10417b719 <+41>: movl   %edx, %eax
    0x10417b71b <+43>: addq   $0x10, %rsp
    0x10417b71f <+47>: popq   %rbp
    0x10417b720 <+48>: retq

栈帧

  • 栈帧指的是 sp和bp之间的空间 8086CPU中栈帧很明显就可以看到, 不过64位的CPU中 由于寄存器得到充分的运用, 所以栈帧不是每次函数调用都可以出现的

全局变量

image.png
  • 如上图所示, 全局变量相对于app来说, 其偏移地址一直是固定不变的, 而基地址是基于整个app在内存中的物理地址来随时改变的

if 判断

int a = 2;
        if (a == 1) {
            NSLog(@"a == 1");
        } else if (a == 2) {
            NSLog(@"a == 2");
        } else if (a == 3) {
            NSLog(@"a == 3");
        } else if (a == 4) {
            NSLog(@"a == 4");
        }
  0x1014926bb <+27>:  movl   $0x2, -0x14(%rbp) ;  赋值
->  0x1014926c2 <+34>:  cmpl   $0x1, -0x14(%rbp) ; cmp = cpmpare 比较
    0x1014926c6 <+38>:  movq   %rax, -0x20(%rbp)
    0x1014926ca <+42>:  jne    0x1014926e6               ; <+70> at main.m:21  ; jne: jump not equl 不等的时候跳转到0x1014926e6指令
    0x1014926d0 <+48>:  leaq   0x1989(%rip), %rax        ; @"a == 1"
    0x1014926d7 <+55>:  movq   %rax, %rdi
    0x1014926da <+58>:  movb   $0x0, %al
    0x1014926dc <+60>:  callq  0x101492a14               ; symbol stub for: NSLog
    0x1014926e1 <+65>:  jmp    0x101492750               ; <+176> at main.m:29
    0x1014926e6 <+70>:  cmpl   $0x2, -0x14(%rbp) 
    0x1014926ea <+74>:  jne    0x101492706               ; <+102> at main.m:23
    0x1014926f0 <+80>:  leaq   0x1989(%rip), %rax        ; @"a == 2"
    0x1014926f7 <+87>:  movq   %rax, %rdi
    0x1014926fa <+90>:  movb   $0x0, %al
    0x1014926fc <+92>:  callq  0x101492a14               ; symbol stub for: NSLog
    0x101492701 <+97>:  jmp    0x10149274b               ; <+171> at main.m
    0x101492706 <+102>: cmpl   $0x3, -0x14(%rbp)
    0x10149270a <+106>: jne    0x101492726               ; <+134> at main.m:25
    0x101492710 <+112>: leaq   0x1989(%rip), %rax        ; @"a == 3"
    0x101492717 <+119>: movq   %rax, %rdi
  • 以上代码是if判断的汇编实现, 问题来了, jne的时候 怎么判断是否相等而去跳转呢?
    • 是用标记寄存区来存放比较的结果的:


      image.png
      • 如上图, cmp前后 如果rflags值没有发生改变, 说明并不相等; 若发生改变, 说明相等
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 原文地址:C语言函数调用栈(一)C语言函数调用栈(二) 0 引言 程序的执行过程可看作连续的函数调用。当一个函数执...
    小猪啊呜阅读 10,193评论 1 19
  • 8086汇编 本笔记是笔者观看小甲鱼老师(鱼C论坛)《零基础入门学习汇编语言》系列视频的笔记,在此感谢他和像他一样...
    Gibbs基阅读 37,641评论 8 114
  • 春天来了,迈着轻柔的脚步,踩绿了程家冲的山川河流,踩绿了田野,程家子女赏油菜花中,瞧他们沉醉于春天的浓意,陶醉于山...
    xiao程故事阅读 3,122评论 2 0
  • 上一篇关于KVC的讲解中我们说到了KVC提供了一种通过key来访问类的属性以及成员变量的机制。今天要说的KVO是提...
    TyroneTang阅读 1,573评论 0 1
  • 最近有一些品牌方向我咨询,老师,我经常听到直营微商,直营模式,什么是直营模式? 那今天就和大家讨论一下微商企业直营...
    龚川腾阅读 3,641评论 0 0