04 局部变量的空间分配及栈回收重用之汇编分析

来源:互联网 发布:后端用java还是php 编辑:程序博客网 时间:2024/06/05 09:06

估计每个人在学C语言时被告之:当函数里的代码执行时,函数体内的局部变量会在栈里分配空间,函数执行结束时回收所分配的空间。
但具体是怎样分配,怎样的回收,这些问题就只能发挥想象力了,学会汇编后,其实我们就可以更加的直观地去了解。

对栈不熟悉的话,可以参考程序的段,堆与栈

1). 局部变量的分配空间

   test.c        1     2 int main(void)    3 {    4     int a = 56, b = 77;    5     6     7     return 0;    8 }  编译后,用arm编译器的objdump工具得到汇编代码:    0000839c <main>:        839c:       e52db004        push    {fp}            ; (str fp, [sp, #-4]!) //为调用main函数的调用者备份fp寄存器的内容,因下面需改变它的值        83a0:       e28db000        add     fp, sp, #0    //用fp寄存器存放栈顶最初的位置 , 函数执行时,再把fp寄存器的位置恢复到sp寄存器里,即栈回收了        83a4:       e24dd00c        sub     sp, sp, #12    //在栈里分配空间,用于局部变量a, b.  相当于int a, b;        83a8:       e3a03038        mov     r3, #56 ; 0x38        83ac:       e50b3008        str     r3, [fp, #-8]   // (fp-8)的位置即是变量a的地址,这里是给局部变量a赋值. a = 56        83b0:       e3a0304d        mov     r3, #77 ; 0x4d        83b4:       e50b300c        str     r3, [fp, #-12]  // (fp-12)的位置即是变量b的地址, 给变量b赋值. b = 77;        83b8:       e3a03000        mov     r3, #0        83bc:       e1a00003        mov     r0, r3         //返回值放到r0        83c0:       e28bd000        add     sp, fp, #0     //函数结束前恢复栈顶位置. 即局部变量a,b所分配的空间被回收了.        83c4:       e8bd0800        ldmfd   sp!, {fp}      //恢复fp寄存器的内容        83c8:       e12fff1e        bx      lr             //跳回到返回地址.  mov   pc, lr

2). 函数的参数也是局部变量

   test.c      1       2 void func(int aa)      3 {      4     aa = 89;      5 }      6       7 int main(void)      8 {      9      10     return 0;     11 }  编译后的反汇编代码:    0000839c <func>:        839c:       e52db004        push    {fp}            ; (str fp, [sp, #-4]!)        83a0:       e28db000        add     fp, sp, #0        83a4:       e24dd014        sub     sp, sp, #20        83a8:       e50b0010        str     r0, [fp, #-16]        83ac:       e3a03059        mov     r3, #89 ; 0x59        83b0:       e50b3008        str     r3, [fp, #-8]   // aa = 89; 由此可见函数参数是在栈里分配空间的,也是一个局部变量来的        83b4:       e28bd000        add     sp, fp, #0        83b8:       e8bd0800        ldmfd   sp!, {fp}        83bc:       e12fff1e        bx      lr

3). 栈回收重用的问题

    test.c      1       2 #include <stdio.h>      3       4 void func2()      5 {      6     int a, b;      7       8     printf("a = %d, b = %d\n", a, b);      9 }     10      11 void func()     12 {     13     int aa = 33, bb = 44;     14 }     15      16 int main(void)     17 {     18     func();  //先执行函数func     19     func2(); //再执行函数func2     20     return 0;     21 }   程序编译后执行的输出: a = 33, b = 44;   反汇编后的代码:    000083f8 <func>: //先执行func函数        83f8:       e52db004        push    {fp}            ; (str fp, [sp, #-4]!)        83fc:       e28db000        add     fp, sp, #0   //用fp寄存器记录栈顶位置         8400:       e24dd00c        sub     sp, sp, #12  //栈分配12字节        8404:       e3a03021        mov     r3, #33 ; 0x21        8408:       e50b3008        str     r3, [fp, #-8]   // func函数里的 aa = 33;        840c:       e3a0302c        mov     r3, #44 ; 0x2c        8410:       e50b300c        str     r3, [fp, #-12]  // func函数里的 bb = 44;        8414:       e28bd000        add     sp, fp, #0    //栈顶位置从fp寄存器恢复, aa和bb变量的空间已回收,但原来位置上的值不变        8418:       e8bd0800        ldmfd   sp!, {fp}        841c:       e12fff1e        bx      lr    000083d0 <func2>: //func函数执行后,func2函数接着执行        83d0:       e92d4800        push    {fp, lr}  //注意,这里多压栈一个寄存器的内容        83d4:       e28db004        add     fp, sp, #4  //这里sp+4刚好对上 func函数里"add     fp, sp, #0"语句时的栈顶位置         83d8:       e24dd008        sub     sp, sp, #8        83dc:       e59f0010        ldr     r0, [pc, #16]   ; 83f4 <func2+0x24>        83e0:       e51b1008        ldr     r1, [fp, #-8]   //这里的(fp-8)对应func函数里的(fp-8), 取出的值就是33        83e4:       e51b200c        ldr     r2, [fp, #-12]  //这里的(fp-12)对应func函数里的(fp-12), 取出的值就是44        83e8:       ebffffb5        bl      82c4 <_init+0x20>  //调用printf函数        83ec:       e24bd004        sub     sp, fp, #4        83f0:       e8bd8800        pop     {fp, pc}        83f4:       00008490        muleq   r0, r0, r4
阅读全文
0 0