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

估计每个人在学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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值