变量存放在哪里?
文章作者:cdeng
/*程序1*/
unsigned int n;
void f1();
int f2(int,int);
void far f3();
main()
{
n=0;
f1();
n=f2(1,2);
f3();
}
void f1(){n=1;}
int f2(int a,int b)
{
int c;
c=a+b;
return c;
}
void far f3()
{
n=10;
}
把程序1用tcc.exe编译生成exe,然后用debug装载该exe文件,t一下,然后用u命令查看1fa处的代码,第一句语句:
MOV WORD PTR [01A6],0000
对应源程序main()函数中的n = 0 指令,显然n的段地址在ds寄存器中,下面接着是一条调用f1()子函数的代码,再下面的指令如下:
MOV AX,0002
PUSH AX
MOV AX,0001
PUSH AX
CALL 0220
显然这是把实参1,2通过ax放入栈中,然后调用f2()子函数,接着我查看220处的代码,f2()子函数的代码如下:
PUSH BP
MOV BP,SP
PUSH SI
MOV SI,[BP+04]
ADD SI,[BP+06]
MOV AX,SI
JMP 022E
POP SI
POP BP
RET
第二条mov指令后是取出1放入si,接着把2加到si,参数的存放地址偏移基地址都是bp,默认段地址是ss,所以参数的段地址在ss中,可以看出加完以后就是c的值,然后把值给了ax,返回1fa处可以看到,直接用ax把值传给了n。这四个变量中n是全局变量,它的存储空间在ds中,参数的存储空间也在ss段中,函数的返回值放在ax中,也就是说函数的返回值存储在寄存器中。
可以看出全局变量在没有执行以前就分配到了地址,因为它的偏移地址是确定的数值,也就是说全局变量在编译连接好就分配到了地址,参数的偏移地址有寄存器做基地址,也就是说参数是在运行中使用到的时候才分配到地址。
可以看出在整个main()函数和三个子程序中都没有释放[01a6]处的内存,也就是说在整个程序执行完的那一刻全局变量的存储空间才会释放掉。从上面f2()的函数代码中可以看到在ret前面有连续两个pop指令,把参数分配到的内存释放掉了,也就是说参数的存储空间在它被使用到的子函数段结束前的最后一刻释放掉。
从这个程序我无法判断出局部变量是否分配了内存空间,于是我在函数f2()中开始的时候添了一句代码 a = b,经过查看我发现它的对应代码是:
MOV AX,[BP+06]
MOV [BP+04],AX
也就是说局部变量a的内存空间是[BP+04],说明局部变量分配到了空间,可以知道局部变量的存储空间也在ss段中,由于a的地址和参数1的地址相同,所以释放参数地址的时候把a的地址也释放了,可以推断出局部变量的存储空间也是在它所在函数段结束前一刻释放。
查看f3()的代码可以发现它用retf指令来返回,而f1()和f2()都是用的ret指令来返回,也就是说f3()用的远返回,而f1()和f2()近返回,说明编译器认为f3()与调用点的距离需要进行段间的跳动。但是实际计算我发现它们的距离并不需要使用远转移。
综上研究我得出的结论是:
全局变量 局部变量 参数
存储空间 DS SS SS
分配时机 编译完成,运行前 使用到时 使用到时
释放时机 整个程序执行完时 所在函数段完成 所在函数段完成
发表日期:2012年05月27日
网友评论(0)
当前1/1页 首页 上一页下一页 尾页