2024年Go最新《伏C录》凝丹篇-函数栈帧理解手册_栈枝1,2024年最新Golang面试真题解析火爆全网

img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Go语言开发知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

如果你需要这些资料,可以戳这里获取

出栈:将栈顶指针向下移动四字节,这里的向下是往低地址处移动四个字节的空间。并将这四个字节的数据放入某个寄存器中。

出栈指令:pop a。

图解:以pop  a为例。

简单汇编操作指令

mov a b:将b赋值给a,c语言表示就是a=b。

sub a b:将a-b的结果赋值给a,c语言表述就是a=a-b。

add a b :将a+b的结果赋值给a,c语言表述就是a=a+b。

由于理解成本的原因,遇到的其它汇编指令本文会直接指出它的作用效果。

三、栈帧创建与销毁

以Add函数调用为例

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int Add(int x, int y)
{
	int z = x + y;
	return z;
}
int main()
{
	int a = 10;
	int b = 20;
	int z = 0;
	z = Add(a, b);
	printf("%d\n", z);
	return 0;
}

该代码对应的汇编指令如下:

需要说明的是,main函数也被别的函数调用的,调用关系是:__mainCRTStartup调用main函数,mainCRTStartup函数调用__mainCRTStartup。

再调用main函数之前,栈区是这样的。

指令分说:

int main()
{
00F71E40  push        ebp  
00F71E41  mov         ebp,esp  
00F71E43  sub         esp,0E4h  

以上图为参照。

第一条指令:将寄存器ebp的值压栈

第二条指令:将寄存器esp的值赋值给ebp

第三条指令:将esp-0E4h赋值给寄存器esp,形象的表述是esp向低地址方向移动4个字节,上端为低地址,下端为高地址,即向上移动4字节空间。

栈区视图变为:

这三条指令,简单来说就是为main函数在栈区开辟了一块空间(这块空间大小系统会帮我们自动开辟好。)

指令分说:

00F71E49  push        ebx  
00F71E4A  push        esi  
00F71E4B  push        edi  

将三个寄存器的值压入栈中

栈区视图变为:

指令分说:

00F71E4C  lea         edi,[ebp-24h]  
00F71E4F  mov         ecx,9  
00F71E54  mov         eax,0CCCCCCCCh  
00F71E59  rep stos    dword ptr es:[edi] 

这四条指令我们就解读了,效果就是将main函数的栈帧空间以16进制值cccccccc填充。

栈区视图变为:

指令分说:

00F71E5B  mov         ecx,0F7C003h  
00F71E60  call        00F7130C 

这两条指令是编译器检查用的,初学不必花费更多时间了解更细节的部分。

vs2013没有这一检查部分,vs2019检查很严格。

指令分说:

int a = 10;
00F71E65  mov         dword ptr [ebp-8],0Ah  
	int b = 20;
00F71E6C  mov         dword ptr [ebp-14h],14h  
	int z = 0;
00F71E73  mov         dword ptr [ebp-20h],0  

第一条汇编指令:将0Ah放入[ ebp-8 ]这块空间中,即把a放入那块空间。

第二条汇编指令:将14h放入[ ebp-14h ]这块空间中,即把b放入那块空间中。

第三条汇编指令:将0放入[ ebp-20h ]这块空间中。即把z放入那块空间中。

栈区图示:

简单来说:就是将局部变量放入对应的函数栈帧中。

指令分说:

z = Add(a, b);
00F71E7A  mov         eax,dword ptr [ebp-14h]  
00F71E7D  push        eax  
00F71E7E  mov         ecx,dword ptr [ebp-8]  
00F71E81  push        ecx  

第一条指令:将【ebp-20】这块空间4字节的数据放入eax中。即把b=20的数据放入eax中。

第二条指令:将eax的数据压栈。

第三条指令:将【ebp-8】这块空间4字节的数据放入ecx中。即把a=10的数据放入ecx中。

第四条指令:将ecx的数据压栈。

栈区视图:

这里的20和10,就是我们传过去的实参,之后Add函数调用的x和y就是指这两块空间。

那么我们可以知道:函数传参是从右向左传的。这里就是先传的b再传的a。

指令分说:

00F71E82  call        00F710B4 

调用的函数:
int Add(int x, int y)
{
00F71740  push        ebp  
00F71741  mov         ebp,esp  
00F71743  sub         esp,0CCh  
00F71749  push        ebx  
00F7174A  push        esi  
00F7174B  push        edi  
00F7174C  lea         edi,[ebp-0Ch]  
00F7174F  mov         ecx,3  
00F71754  mov         eax,0CCCCCCCCh  
00F71759  rep stos    dword ptr es:[edi]  
00F7175B  mov         ecx,0F7C003h  
00F71760  call        00F7130C  
	int z = x + y;
00F71765  mov         eax,dword ptr [ebp+8]  
00F71768  add         eax,dword ptr [ebp+0Ch]  
00F7176B  mov         dword ptr [ebp-8],eax  
	return z;
00F7176E  mov         eax,dword ptr [ebp-8]  
}
00F71771  pop         edi  
00F71772  pop         esi  
00F71773  pop         ebx  
00F71774  add         esp,0CCh  
00F7177A  cmp         ebp,esp  
00F7177C  call        00F71235  
00F71781  mov         esp,ebp  
00F71783  pop         ebp  
00F71784  ret  

第一条汇编指令:call是调用指令,调用Add函数。

经过上次的指令,这里我就直接介绍效果了。

00F71740  push        ebp  
00F71741  mov         ebp,esp  
00F71743  sub         esp,0CCh  

这三条指令,为Add函数在栈区开辟对应的空间大小。

栈区图示:

00F71749  push        ebx  
00F7174A  push        esi  
00F7174B  push        edi  

将ebx,esi,edi入栈。

图示:

00F7174C  lea         edi,[ebp-0Ch]  
00F7174F  mov         ecx,3  
00F71754  mov         eax,0CCCCCCCCh  
00F71759  rep stos    dword ptr es:[edi]  

对Add函数栈帧做初始化,将里面的数据置换为cccccccc。(用于初始化栈帧的具体数值取决于编译器)

00F7175B  mov         ecx,0F7C003h  
00F71760  call        00F7130C  

编译器做的检查,不必理会。

int z = x + y;
00F71765  mov         eax,dword ptr [ebp+8]  
00F71768  add         eax,dword ptr [ebp+0Ch]  
00F7176B  mov         dword ptr [ebp-8],eax  

取[ebp+8]空间的数据放入eax中

取 [ebp+0Ch]  与eax的数据相加后放入eax中。

将eax的值放入ptr [ebp-8]中。

图示:

 return z;
00F7176E  mov         eax,dword ptr [ebp-8]  

返回时,通过寄存器的方式,将返回值交给寄存器。

img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Go语言开发知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

如果你需要这些资料,可以戳这里获取

word ptr [ebp-8]


返回时,通过寄存器的方式,将返回值交给寄存器。



[外链图片转存中…(img-ycJoMbpX-1715641142366)]
[外链图片转存中…(img-H4iO64fK-1715641142367)]
[外链图片转存中…(img-J4k2BaRe-1715641142367)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Go语言开发知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

如果你需要这些资料,可以戳这里获取

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值