上次由于时间问题,只学习了研究试验3的一部分内容,现在就把后面的三个题目的学习和思考过程继续贴出来交流。
实践学习题目(3),思考问题:C语言的全局变量、局部变量存放在哪里?每个函数开头的“push bp mov bp,sp”有什么作用。
我们编译连接书上的代码,然后反汇编进行研究,反汇编代码及分析如下:
;main函数部分
1413:01FA 55 PUSH BP
;这里不用说,是保存BP的原始值(作用还得往下看)
1413:01FB 8BEC MOV BP,SP
;这里是将sp的值赋值给BP,那么SS:BP和SS:SP此时指向了同一位置。()
1413:01FD 83EC06 SUB SP,+06
;将栈空间空出3个字的内存空间来,干什么?看看下面的局部变量赋值就知道了。
1413:0200 C706A601A100 MOV WORD PTR [01A6],00A1
1413:0206 C706A801A200 MOV WORD PTR [01A8],00A2
1413:020C C706AA01A300 MOV WORD PTR [01AA],00A3
;以上三条指令是给全局变量a1,a2,a3赋值,根据汇编的源代码可以看出,这种寻址方式默认的段寄存器是ds,全局变量是存放在段地址为ds的内存空间中的。
1413:0212 C746FAB100 MOV WORD PTR [BP-06],00B1
1413:0217 C746FCB200 MOV WORD PTR [BP-04],00B2
1413:021C C746FEB300 MOV WORD PTR [BP-02],00B3
;以上三条指令是给局部变量b1,b2,b3赋值,根据汇编代码,用BP寻址默认的段寄存器是ss,而ss是程序运行时候的栈的段地址,所以,可以推断,局部变量是存放在了程序的栈空间。(这里也就知道了sub sp,6的指令的作用了,空出来三个字单元内存,然后,将三个局部变量的值依次存放到这段栈空间内,存放的时候就用到了BP来定位,也就是,那三个子单元空间是在sp和bp之间的。可以细细体会一下bp的用处了吧,临时的定位。还有作用呢,别急,向下看)
1413:0221 E80400 CALL 0228
;为了准确的定位f函数的位置,我在源代码中加了一个f()来调用f函数。
1413:0224 8BE5 MOV SP,BP
;程序运行完毕了,局部变量的生命周期也该结束了,BP的另一个作用又出现了:恢复SP的值。因为局部变量已经结束了自己的作用范围了,所以,就可以释放了,怎么释放呢?我们知道sp和bp之间是存储的局部变量,要想把这段栈空间空闲出来,那么就可以pop掉那几个局部变量,当然,还有一个更简单的办法,我们既然在存出局部变量之前,用BP记录了当时sp的值,那么,我们直接再来个mov sp,bp就OK。所以,这里这条的指令就是释放局部变量占用的栈空间。
1413:0226 5D POP BP
;恢复BP为函数进入前的原始值,这是汇编子程序的处理方式。
1413:0227 C3 RET
;f函数部分
1413:0228 55 PUSH BP
1413:0229 8BEC MOV BP,SP
1413:022B 83EC06 SUB SP,+06
;以上三条指令的作用以及跟下面指令的关联和main函数一样,就不在复述。
1413:022E C706A601A10F MOV WORD PTR [01A6],0FA1
1413:0234 C706A801A20F MOV WORD PTR [01A8],0FA2
1413:023A C706AA01A30F MOV WORD PTR [01AA],0FA3
;这里是给全局变量a1,a2,a3赋值,我们可以看出,跟main函数的一样,这些数据放到了段地址默认为ds的内存空间内。说明,全局变量都是存放到这段内存空间的。
1413:0240 C746FAC100 MOV WORD PTR [BP-06],00C1
1413:0245 C746FCC200 MOV WORD PTR [BP-04],00C2
1413:024A C746FEC300 MOV WORD PTR [BP-02],00C3
;f函数中局部变量c1,c2,c3进行赋值,跟main函数的一样,这里的局部变量也是存放到了栈中间中,存放的方式方法也完全一样。
1413:024F 8BE5 MOV SP,BP
1413:0251 5D POP BP
1413:0252 C3 RET
上面对函数的汇编代码进行了分析,知道了局部变量是存放到了当前栈空间中,但是,全局变量是什么段呢?我们知道其段地址是ds,那么我们就看看ds指向的是哪里。在汇编的学习过程中,我们知道,一般ds指向的是我们数据段,但是到底是不是呢?前段时间大概的学习了一下汇编网训练营的C教程,预备知识里有一个自己实现的启动代码,通过对那个启动代码的了解,可以知道,ds在程序的初始化时,指向的就是该程序的数据段(至少现在的C程序应该是这样的),所以,我们可以说全局变量是存放在数据段的。
下面,我们通过实践程序(4)来了解一下,C语言中的返回值是怎么处理的。
将书中的实践代码进行编译、连接,debug下查看其汇编代码如下:
1413:01FA 55 PUSH BP
1413:01FB 8BEC MOV BP,SP
1413:01FD 83EC02 SUB SP,+02
1413:0200 E80700 CALL 020A
1413:0203 8946FE MOV [BP-02],AX;将ax中的值赋值到局部变量c对应的内存单元。
1413:0206 8BE5 MOV SP,BP
1413:0208 5D POP BP
1413:0209 C3 RET
1413:020A 55 PUSH BP
1413:020B 8BEC MOV BP,SP
1413:020D A1A601 MOV AX,[01A6];将a变量的值放入ax
1413:0210 0306A801 ADD AX,[01A8];ax+b变量的值
1413:0214 A3AA01 MOV [01AA],AX;将ax放入ab变量的内存地址
1413:0217 A1AA01 MOV AX,[01AA];将ab变量的内存中的值放入ax
1413:021A EB00 JMP 021C
1413:021C 5D POP BP
1413:021D C3 RET
从上面的分析可以看出,在f函数中,ax寄存器贯穿于函数内外,函数内没有对其进行先保存在恢复的操作,所以,ax被用作了一个能够将函数中的操作结果带到函数外部的存储器,也就是我们用来保存返回值的寄存器,而我们从main函数中的指令call 020A后面的那个给c赋值的指令 mov [bp-02], ax也很明显的可以看出,寄存器ax是c程序中用来存放函数返回值的地方。
最后的第(5)个实践程序,是让我们对之前的知识进行理解。
首先我们理解一下第一行代码:
#define Buffer ((char *)*(int far *)0x0200000)
首先这是一条宏指令,程序中的Buffer,都能用后面的字符串((char *)*(int far *)0x0200000)进行物理替换。关键是((char *)*(int far *)0x0200000)怎么理解。我就说一下我的理解。
从右向左,(int far *)0x0200000将一个16进制的数据强制转换成一个长指针;*(int far *)0x0200000相当于取这个长指针变量对应的地址处的值;然后((char *)*(int far *)0x0200000)),将长指针指向的内存空间中的值转换成一个char型指针。一句话概括一下:地址为0x02000000处的内存空间中存放着一个char型指针。再往明白了说就是,Buffer代表的就是一个char型指针。#define Buffer ((char *)*(int far *)0x0200000)相当于 char * Buffer。
接下来的程序就不难理解了
main(){
Buffer=(char *)malloc(20);
;有了上面的结论,这里不难理解了,就是申请了20个字节的内存空间。malloc是申请空间的,然后返回空间的首地址。
Buffer[10]=0;
;这里就奇怪了,这是数组的使用形式,而我们没有定义数组。哈哈。牛就牛在这了。以前的学C的理解太死板,太肤浅了。其实,数组的实现是基于指针的,数组名就是代表了数组的首地址。“地址+[下标]” 这个寻址形式很类似我们的汇编中的基址变址寻址的形式。“地址+[下标]”代表的意义:操作“地址+下标值”这个地址处的数据。所以,这行代码的作用就是将申请到的内存中的第10号(游标号从0开始)的char型数据直接赋值为0。
while(Buffer[10]!=8){
;我们知道,不论字符还是什么,在内存中都是以数据的行是存放,所以,这里可以用字符指针指向的内存中的数据值与循环控制次数做比较,进行判断。
Buffer[Buffer[10]] = 'a'+Buffer[10];
;因为Buffer[10]从0开始变化,所以,可以将其作为游标,然后以字符'a'的值与Buffer[10]当前的值来使字符从a变到h。
Buffer[10]++;
;Buffer[10]处的内存中的值进行子增变化。
}
}
上面的这段程序非常的巧妙,而且,理解起来有点绕,我也不知道我说的清楚不清楚,总之,通过这个实践任务,我知道了指针可以跟数组一样,用下标来控制和变化,这个真是长见识了,那个C语言教程上也没见过这个啊。呵呵。还得细细品味品味。如果那个兄弟品的更有味道,指教小弟一二。再次做谢啦!
=================================
研究试验一个比一个有味道了。还得多体会一下啊。
下个就是研究试验4了。
准备中。。。 |