美文网首页
栈里面的红色区域

栈里面的红色区域

作者: stockholder | 来源:发表于2017-07-28 02:37 被阅读0次

    红色区域概念

    当一个函数里面没有调用其他函数时,在函数的内部会有一块区域用来存储局部变量和参数,这块区域就叫红色区域(默认区域大小是128字节)

    下面的例子是用来说明编译器是如何处理函数内部有其他函数调用和没有其他函数调用的的。
    • 函数内部不调用其他函数时的情况
    int test1(int a,int b) {
        int c = 3;
        int d = 4;
        int e = a + b +c +d;
        return e;
    }
    
    int main(int argc, char * argv[]) {
            int m = test1(1, 2);
            NSLog(@"%d",m);
    }
    

    上面是一个简单的函数定义,看一下test1()内部的反汇编代码

    RedDistinct`test1:
        0x100f2c990 <+0>:  pushq  %rbp
        0x100f2c991 <+1>:  movq   %rsp, %rbp
        0x100f2c994 <+4>:  movl   %edi, -0x4(%rbp)
        0x100f2c997 <+7>:  movl   %esi, -0x8(%rbp)
    ->  0x100f2c99a <+10>: movl   $0x3, -0xc(%rbp)
        0x100f2c9a1 <+17>: movl   $0x4, -0x10(%rbp)
        0x100f2c9a8 <+24>: movl   -0x4(%rbp), %esi
        0x100f2c9ab <+27>: addl   -0x8(%rbp), %esi
        0x100f2c9ae <+30>: addl   -0xc(%rbp), %esi
        0x100f2c9b1 <+33>: addl   -0x10(%rbp), %esi
        0x100f2c9b4 <+36>: movl   %esi, -0x14(%rbp)
        0x100f2c9b7 <+39>: movl   -0x14(%rbp), %eax
        0x100f2c9ba <+42>: popq   %rbp
        0x100f2c9bb <+43>: retq 
    

    通过汇编代码分析,此时sp寄存器没有开辟栈空间来放这些参数和局部变量,是通过是通过bp指针减来存放参数和局部变量(直接从寄存器取值放到栈里面),那么如果这样的话,当调用其他函数时,不是会push到栈里面,将参数或者是局部变量覆盖了?那么实际的情况又是怎样的呢?

    屏幕快照 2017-07-28 上午1.59.49.png
    • 函数内部调用其他函数时的情况
    void test2() {  
    }
    int test1(int a,int b) {
        int c = 3;
        int d = 4;
        int e = a + b +c +d;
        test2();
        return e;
    }
    int main(int argc, char * argv[]) {
            int m = test1(1, 2);
            NSLog(@"%d",m);
    }
    

    下面是反汇编代码

    RedDistinct`test1:
        0x10556a980 <+0>:  pushq  %rbp
        0x10556a981 <+1>:  movq   %rsp, %rbp
        0x10556a984 <+4>:  subq   $0x20, %rsp
        0x10556a988 <+8>:  movl   %edi, -0x4(%rbp)
        0x10556a98b <+11>: movl   %esi, -0x8(%rbp)
    ->  0x10556a98e <+14>: movl   $0x3, -0xc(%rbp)
        0x10556a995 <+21>: movl   $0x4, -0x10(%rbp)
        0x10556a99c <+28>: movl   -0x4(%rbp), %esi
        0x10556a99f <+31>: addl   -0x8(%rbp), %esi
        0x10556a9a2 <+34>: addl   -0xc(%rbp), %esi
        0x10556a9a5 <+37>: addl   -0x10(%rbp), %esi
        0x10556a9a8 <+40>: movl   %esi, -0x14(%rbp)
        0x10556a9ab <+43>: callq  0x10556a970               ; test2 at main.m:12
        0x10556a9b0 <+48>: movl   -0x14(%rbp), %eax
        0x10556a9b3 <+51>: addq   $0x20, %rsp
        0x10556a9b7 <+55>: popq   %rbp
        0x10556a9b8 <+56>: retq 
    

    可以看到当函数内部有其他函数的调用时,会开辟一块栈空间(通过下面的汇编代码可以看出,开辟了32个字节的栈空间,并且该栈空间会随着参数或者局部变量的数目来增加,这样的方式不用去操作栈,速度快)
    0x10556a984 <+4>: subq $0x20, %rsp
    用来存放这些参数和局部变量,这个时候就不会出现调用其他函数会将局部变量和参数覆盖掉了,编译器还是很聪明的。

    屏幕快照 2017-07-28 上午2.33.02.png
    小结一下:

    当一个函数里面没有调用其他函数时,在函数的内部会有一块区域用来存储局部变量和参数(不会开辟栈空间来存储,但是当128字节不够用的话还是会开辟栈空间),这块区域就叫红色区域,当有调用其他函数时,会开辟栈空间(这块区间也叫做栈帧)来存储局部变量和参数,用来保护参数和局部变量不被覆盖。

    相关文章

      网友评论

          本文标题:栈里面的红色区域

          本文链接:https://www.haomeiwen.com/subject/vcxxlxtx.html