既有适合小白学习的零基础资料,也有适合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]
返回时,通过寄存器的方式,将返回值交给寄存器。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Go语言开发知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新
word ptr [ebp-8]
返回时,通过寄存器的方式,将返回值交给寄存器。
[外链图片转存中…(img-ycJoMbpX-1715641142366)]
[外链图片转存中…(img-H4iO64fK-1715641142367)]
[外链图片转存中…(img-J4k2BaRe-1715641142367)]
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Go语言开发知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新