我是靠谱客的博主 酷酷绿茶,最近开发中收集的这篇文章主要介绍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 = %dn", 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

最后

以上就是酷酷绿茶为你收集整理的04 局部变量的空间分配及栈回收重用之汇编分析的全部内容,希望文章能够帮你解决04 局部变量的空间分配及栈回收重用之汇编分析所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(45)

评论列表共有 0 条评论

立即
投稿
返回
顶部