网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
PS:栈区内存从高地址向低地址走,所以我们等下往上走。
这里我们就可以通过调试里面的内存去看esp的地址里面存放的内容就是ebp的地址
PS:这里预开辟的空间是编译器决定的,我们自己也是不知道的。
PS:当我们压栈的时候esp是会变的。还有上面的那三个值,后面会自己弹出去的。
PS:是从edi那个位置向下的那么多空间。是改成CCCCCCCC哈,上面讲错了。
这上面的就是main函数栈帧的开辟。
接下来就是执行有效代码了。
3.函数的调用
PS:这里我们就可以说到,大家之前遇到过打印随机值的情况吧,
也就是烫烫烫烫烫之类的,在我们没有给那一块空间赋值的时候,
那个地方(如此CCCCCCCC),打印出来就是那样。
这里ab离得有点远,有也有可能是挨着放的,取决于编译器。
后面c也和前面一样。
综上:局部变量a,b,c的创建就是先创建一个函数栈帧,然后在里面找到
一块空间,再把a,b,c放进去。
上面两个动作就是传参,但是还没有讲完,所以现在感受不到。
PS:上面都是按的F10哈,这里call我们要按F11,进入函数内部。
我们记住call指令的下一条指令是因为当我们执行完call指令之后会回来,
回来的时候我们就找到这一条指令然后往下执行。
PS:右边的esp也是要指向最上面的哈。
再按F11,这次就是真正的来到了Add的函数里面。
也就是为我们的Add函数准备栈帧。
下面是我们此时的main函数的栈帧哈:
PS:我们从上还可以找到,函数传参压栈是从右向左传的,
在这里也就是先压b,再压a。
这下面就是xyz的图:
下图就完全可以说明:形参是实参的临时拷贝:
我们开始是在main函数中有a和b,我们通过push a,b 压了上去,也就是x(a‘),y(b’),
这就是临时(栈区)拷贝(压栈)。所以改变形参不会影响实参。
我们函数传参的方式是函数还没有调用的时候,参数就已经过去了,就是压了两个参数,然后当
我们真正进入函数内部的时候我们就找回了之前压的两个参数。然后再计算,计算好的值再放进z里面。
以上就是函数的调用,然后下面开始讲函数的返回。
4.函数的返回
PS:就相当于用一个全局的寄存器先把z保存起来,也就是说安全了(不会消失)。等回到
主函数的时候再把eax拿出来用就可以了。
开始:
PS:一开始栈顶上是main函数的ebp。
结束:
现在就又回到了main函数里面了。
我们上面pop完之后只是要我们的ebp和esp指向了main函数的栈顶和栈底(即main函数
的这一块空间又用我们的ebp和esp开始维护了)。
但是我们回到了main函数之后还是要从call的下一个地址开始执行
怎么回到那里呢(call的下一个地址):
我们的栈顶上除了有main函数的ebp之外,其实还有call指令的下一条指令
其实ret指令就是返回时pop(弹出)call指令的下一条指令
所以说我们当时在栈顶存放call指令的下一条指令就是为了执行完
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
[外链图片转存中…(img-IaoakQvs-1715799172566)]
[外链图片转存中…(img-bqOkxbJc-1715799172566)]
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!