【转】栈桢指针和栈回溯

【转】栈桢指针和栈回溯 编译器设计之路

    函数多使用栈来传递参数和保存局部变量,栈桢就是在一个函数内分配和使用的一段栈上内存,具体来说就
是从进入一个函数的第一条指令时sp所指的位置开始向下所有该函数分配的栈上内存。当调用一个函数时一个新
的栈桢会被创建,这个栈桢的地址立即存放到桢指针(在x86中是ebp寄存器,在arm中是fp(r11)寄存器)中
(这不是必须的),这样对参数和局部变量的访问更方便,并且对于函数回溯很重要。

    在具有栈桢结构的函数中栈桢指针指向当前栈桢或为0(表示这是最顶层的函数了,栈回溯到此函数结束)。

举例:

/*此函数没任何意义*/
    int foo(int a,int b,int c)
    {
        int    d[3];
        d[1] = 0;
   
        return 0;
    }
调用:
    foo(1,2,4);

不优化并生成桢指针的方式编译后代码:
    push        4 
    push        2 
    push        1 
    call        foo 
    add         esp,0Ch
    ... 
foo:
    push        ebp 
    mov         ebp,esp/*桢指针,当前栈桢开始*/ 
    sub         esp,0Ch /*在当前的栈桢上分配局部变量空间12字节*/
 
    mov         dword ptr [ebp-8h],0/*对局部变量的访问使用[ebp-offset]方式*/

    xor         eax,eax  /*返回值为0*/

foo()的栈:
    |参数值4    |
    |参数值2    |
    |参数值1    |
    |返回地址    |
    |调用者桢指针ebp    ||/*foo函数的栈桢*/
    |d[2]        ||
    |d[1]        ||
    |d[0]        ||

栈回溯:
     假如在某个函数中需要回溯时(比如bug了),调用本函数处的地址为[ebp+4],父函数的桢指针为[ebp],得到了
父函数的栈桢,便可进一步向上回溯,直到桢指针为0。

    gcc的-fomit-frame-pointer参数使编译器在不需要桢指针的函数中保持桢指针,这样可避免不必要的保存、
建立和恢复桢指针,并且桢指针寄存器可留作他用。当使用-O选项时此选项会自动选上。
    注意:
        此选项会破坏桢回溯从而使得无法调试。

    -mapcs-frame选项会强制编译器生成ARM过程调用标准兼容的栈桢(尽管在某些函数不需要)。它和
     -fomit-frame-pointer参数同时指定时仅在叶子函数(不调用其他函数)不建立栈桢。对应的Thumb过程调
     用的参数是-mtpcs-frame。若要在叶子函数也生成栈桢可使用-mtpcs-leaf-frame参数。

    -mlinked-fp参数遵从EABI标准,始终创建栈桢指针不管栈桢是否创建,此选项默认是选中的,可用
     -mno-linked-fp参数禁止。

    -mno-backchain参数使得不会把调用者的回溯链地址存入被调用者的栈桢中。

你可能感兴趣的:(【转】栈桢指针和栈回溯)