Bootstrap

【C语言】二十二步了解函数栈帧(压栈、传参、返回、弹栈)

请添加图片描述

002918B3 sub esp,0E4h
esp 减去 0E4h 0E4h == 228
esp = 0x008ff8b4

低地址
| |\ esp 0x008ff8b4
| | \
| | \
| | main
| | /
| | /
| |/
| ebp | ebp 0x008ff998
| |\
| | \
| | __tmainCRTStartup
| | /
| |/
| | 高地址

main函数的空间请添加图片描述

二、压栈

002918B9 push ebx
002918BA push esi
002918BB push edi

esp每次压栈后会自动指向最低地址处
EBX 是"基地址"(base)寄存器, 在内存寻址时存放基地址。
ESI/EDI分别叫做"源/目标索引寄存器"
暂时不理解没关系,直接看三

低地址
| edi | esp 0x008ff8a8
| esi | ↑ 0x008ff8ac
| ebx | ↑ 0x008ff8b0
| |\ ↑ 0x008ff8b4
| | \
| |
| | main
| | /
| | /
| | /
| | /
| |/
| ebp | ebp 0x008ff998
| |\
| | \
| | __tmainCRTStartup
| | /
| |/
| | 高地址

请添加图片描述请添加图片描述
请添加图片描述

三、初始化main函数

002918BC lea edi,[ebp-24h]
002918BF mov ecx,9
002918C4 mov eax,0CCCCCCCCh
002918C9 rep stos dword ptr es:[edi]

edi存储ebp减24h的位置,24hmain函数空间的大小
ecx存储9
eax存储0CCCCCCCCh
ebpedi存储的位置的ecx(9)个位置都 初始化为eax(0CCCCCCCCh)
讲人话就是 :将main空间的内容初始化为cc cc cc cc

低地址
| edi | esp 0x008ff8a8
| esi | ↑ 0x008ff8ac
| ebx | ↑ 0x008ff8b0
|cc cc cc cc|\ ↑ 0x008ff8b4
|cc cc cc cc| \
|cc cc cc cc|
|cc cc cc cc| main
|cc cc cc cc| /
|cc cc cc cc| /
|cc cc cc cc| /
|cc cc cc cc| /
|cc cc cc cc|/
| ebp | ebp 0x008ff998
| |\
| | \
| | __tmainCRTStartup
| | /
| |/
| | 高地址

002918BC lea edi,[ebp-24h]
[ebp-24h] 加载到 edi
002918BF mov ecx,9
把9放到ecx里
002918C4 mov eax,0CCCCCCCCh
eax赋值为0CCCCCCCCh
002918C9 rep stos dword ptr es:[edi]
从edi的位置开始向下的eax这么多个 dword(4byte) 全部改成eax的值

请添加图片描述

四、在main中创建变量a并存储

int a = 10;
002918D5 mov dword ptr [ebp-8],0Ah

a变量的值存到main开辟的空间中, 位置是([ebp-8])的位置
内存中的 |0a 00 00 00| 中的a十六进制代表10 是a的数值的意思,并不是变量a

低地址
| edi | esp 0x008ff8a8
| esi |
| ebx |
|cc cc cc cc|\
|cc cc cc cc|
|cc cc cc cc|
|cc cc cc cc| main
|cc cc cc cc| /
|cc cc cc cc| /
|cc cc cc cc| /
|0a 00 00 00| / ebp-8 0x008FF990
|cc cc cc cc|/
| ebp | ebp 0x008ff998
| |\
| | \
| | __tmainCRTStartup
| | /
| |/
| | 高地址

int a = 10;
002918D5 mov dword ptr [ebp-8],0Ah
ebp - 8 的位置放 一个10进去 0Ah == 10

请添加图片描述

五、在main中创建变量b并存储

int b = 20;
002918DC mov dword ptr [ebp-14h],14h

b变量的值存到main开辟的空间中, 位置是([ebp-14h])的位置
内存中的 |14 00 00 00| 中的14十六进制代表20

低地址
| edi | esp 0x008ff8a8
| esi |
| ebx |
|cc cc cc cc|
|cc cc cc cc|
|cc cc cc cc| \
|cc cc cc cc| main
|14 00 00 00| b / ebp-14h 0x008FF984
|cc cc cc cc| /
|cc cc cc cc| /
|0a 00 00 00| / a ebp-8 0x008FF990
|cc cc cc cc|/
| ebp | ebp 0x008ff998
| |\
| | \
| | __tmainCRTStartup
| | /
| |/
| | 高地址

int b = 20;
002918DC mov dword ptr [ebp-14h],14h
把b放在 ebp-20的位置 14h == 20

请添加图片描述

六、在main中创建变量c并存储

int c = 0;
002918E3 mov dword ptr [ebp-20h],0

c变量的值存到main开辟的空间中, 位置是([ebp-20h])的位置

低地址
| edi | esp 0x008ff8a8
| esi |
| ebx |
|cc cc cc cc|
|00 00 00 00| \ c ebp-20h 0x008FF978
|cc cc cc cc| \
|cc cc cc cc| main
|14 00 00 00| /b ebp-14h 0x008FF984
|cc cc cc cc| /
|cc cc cc cc| /
|0a 00 00 00| / a ebp-8 0x008FF990
|cc cc cc cc|/
| ebp | ebp 0x008ff998
| |\
| | \
| | __tmainCRTStartup
| | /
| |/
| | 高地址

int c = 0;
002918E3 mov dword ptr [ebp-20h],0
将ebp-20h的位置存放c

请添加图片描述


此时:完成了main函数 的开辟, int a = 10; int b = 20; int c = 0; 的创建。
接下来:是将ab的值做临时拷贝, 为Add函数开辟空间。


七、函数传参:将b压栈

c = Add(a, b);
002918EA mov eax,dword ptr [ebp-14h]
002918ED push eax

[ebp-14h]位置上的值(b)存储到eax
eax进行压栈
.
为调用Add函数做准备 因为传参是a b 所以将a b 先压栈到栈区 以便后面调用
EAX寄存器也称为累加器
push压栈操作

低地址
| |
|14 00 00 00| b esp 0x008ff8a4
| edi | 0x008ff8a8
| esi |
| ebx |
|cc cc cc cc|
|00 00 00 00| \ c ebp-20h 0x008FF978
|cc cc cc cc| \
|cc cc cc cc| main
|14 00 00 00| /b ebp-14h 0x008FF984
|cc cc cc cc| /
|cc cc cc cc| /
|0a 00 00 00| / a ebp-8 0x008FF990
|cc cc cc cc|/
| ebp | ebp 0x008ff998
| |\
| | __tmainCRTStartup
| |/
| | 高地址

c = Add(a, b);
002918EA mov eax,dword ptr [ebp-14h]
002918ED push eax
将[ebp-14h]的值放在eax寄存器上 再将eax压栈

请添加图片描述

八、函数传参:将a压栈

002918EE mov ecx,dword ptr [ebp-8]
002918F1 push ecx

[ebp-8](a)的值存在ecx
ecx进行压栈
ECX 是计数器(counter), 是重复(REP)前缀指令和LOOP指令的内定计数器。

低地址
|0a 00 00 00| ecx(a) esp 0x008ff8a0
|14 00 00 00| eax(b) 0x008ff8a4
| edi | 0x008ff8a8
| esi |
| ebx |
|cc cc cc cc|
|00 00 00 00| \ c ebp-20h 0x008FF978
|cc cc cc cc| \
|cc cc cc cc| main
|14 00 00 00| /b ebp-14h 0x008FF984
|cc cc cc cc| /
|cc cc cc cc| /
|0a 00 00 00| / a ebp-8 0x008FF990
|cc cc cc cc|/
| ebp | ebp 0x008ff998
| |\
| | __tmainCRTStartup
| |/
| | 高地址

002918EE mov ecx,dword ptr [ebp-8]
002918F1 push ecx
将ebp-8(a) 的值存放在ecx 将ecx压栈

请添加图片描述

九、压栈call的下一条指令的地址

002918F2 call 002910B4
002918F7 add esp,8

压栈call指令 的下一条指令的地址 为了返回时继续执行代码
因为此语句执行完 会进入Add函数
首先记住你call下一条指令的地址

这里002918F7一会,会被存储到途中箭头所指向的位置请添加图片描述
此时压栈成功 跳到函数里 可以看到002918F7以小端的形式存储到内存中
小端存储:将低位字节存放在低地址处 请添加图片描述

002918F2 call 002910B4
002918F7 add esp,8
call执行后 下一条指令的地址会被压栈

低地址
|f7 18 29 00| call的下一条指令 esp 0x008FF89C
|0a 00 00 00| ecx(a) 0x008ff8a0
|14 00 00 00| eax(b) 0x008ff8a4
| edi | 0x008ff8a8
| esi |
| ebx |
|cc cc cc cc|
|00 00 00 00| \ c ebp-20h 0x008FF978
|cc cc cc cc| \
|cc cc cc cc| main
|14 00 00 00| /b ebp-14h 0x008FF984
|cc cc cc cc| /
|cc cc cc cc| /
|0a 00 00 00| / a ebp-8 0x008FF990
|cc cc cc cc|/
| ebp | ebp 0x008ff998
| |\
| | __tmainCRTStartup
| |/
| | 高地址



此时的反汇编代码:是VS2019的底层逻辑跳转的意思 跳转到地址00291770的位置
继续按下F11会跳转都以下界面

(借用一下,下面语句的图,此时你看到了Add函数 ,就可以继续阅读反汇编指令了)请添加图片描述



十、进入函数内部

此时你又看到了一大堆 反汇编代码

好家伙 差点劝退有没有
到这里我们已经进行的45%
以下代码 看看就好,不用理解 也很简单 跟我一起看下去吧 ヾ(◍°∇°◍)ノ゙

int Add(int x, int y)
{
00291770 push ebp
00291771 mov ebp,esp
00291773 sub esp,0CCh
00291779 push ebx
0029177A push esi
0029177B push edi
0029177C lea edi,[ebp-0Ch]
0029177F mov ecx,3
00291784 mov eax,0CCCCCCCCh
00291789 rep stos dword ptr es:[edi]
0029178B mov ecx,29C003h
00291790 call 0029131B
int z = 0;
00291795 mov dword ptr [ebp-8],0
z = x + y;
0029179C mov eax,dword ptr [ebp+8]
0029179F add eax,dword ptr [ebp+0Ch]
002917A2 mov dword ptr [ebp-8],eax
return z;
002917A5 mov eax,dword ptr [ebp-8]
}
002917A8 pop edi
002917A9 pop esi
002917AA pop ebx
002917AB add esp,0CCh
002917B1 cmp ebp,esp
002917B3 call 00291244
002917B8 mov esp,ebp
002917BA pop ebp
002917BB ret

十一、压栈ebp的地址

00291770 push ebp

ebp 是栈底指针 维护main函数 现在要维护Add函数 所以要向上移动
此代码的意思是:将ebp的地址进行压栈
可以看到内存中|98 f9 8f 00|就是ebp的地址

低地址
|98 f9 8f 00| ebp(main) esp 0x008ff898
|f7 18 29 00| call的下一条指令 0x008FF89C
|0a 00 00 00| ecx(a) 0x008ff8a0
|14 00 00 00| eax(b) 0x008ff8a4
| edi | 0x008ff8a8
| esi |
| ebx |
|cc cc cc cc|
|00 00 00 00| \ c ebp-20h 0x008FF978
|cc cc cc cc| \
|cc cc cc cc| main
|14 00 00 00| /b ebp-14h 0x008FF984
|cc cc cc cc| /
|cc cc cc cc| /
|0a 00 00 00| / a ebp-8 0x008FF990
|cc cc cc cc|/
| ebp | ebp 0x008ff998
| |\
| | __tmainCRTStartup
| |/
| | 高地址

请添加图片描述

十二、让ebp(栈底指针)指向esp(栈顶指针)的位置

00291771 mov ebp,esp

此语句的意思是:ebp = esp
mov(汇编指令)把一个字节、字或双字的操作数从源位置传送到目的位置,源操作数的内容不变。

00291771 mov ebp,esp
把esp的值赋给ebp
让ebp指向现在的esp

低地址
|98 f9 8f 00| main-ebp ebp esp 0x008ff898
|f7 18 29 00| call的下一条指令 0x008FF89C
|0a 00 00 00| ecx(a) 0x008ff8a0
|14 00 00 00| eax(b) 0x008ff8a4
| edi | 0x008ff8a8
| esi |
| ebx |
|cc cc cc cc|
|00 00 00 00| \ c ebp-20h 0x008FF978
|cc cc cc cc| \
|cc cc cc cc| main
|14 00 00 00| /b ebp-14h 0x008FF984
|cc cc cc cc| /
|cc cc cc cc| /
|0a 00 00 00| / a ebp-8 0x008FF990
|cc cc cc cc|/
| ebp | *ebp* 0x008ff998
| |\
| | __tmainCRTStartup
| |/
| | 高地址

请添加图片描述

十三、为Add函数开辟空间

00291773 sub esp,0CCh

esp减去0cch个数值 此操作将esp向上(低地址)移动 , 并开辟出 维护空间

00291773 sub esp,0CCh
将esp - 0CCH
esp向低地址移动 为Add函数开辟空间
低地址
| |
| |
| |
| |\ esp 0x008ff7cc
| |
| |
| |
| |
| |
| | Add
| | /
| | /
| | /
| | /
| | /
| |/
|98 f9 8f 00| main-ebp ebp 0x008ff898
|f7 18 29 00| call的下一条指令 0x008FF89C
|0a 00 00 00| ecx(a) 0x008ff8a0
|14 00 00 00| eax(b) 0x008ff8a4
| edi | 0x008ff8a8
| esi |
| ebx |
|cc cc cc cc|
|00 00 00 00| \ c ebp-20h 0x008FF978
|cc cc cc cc| \
|cc cc cc cc| main
|14 00 00 00| /b ebp-14h 0x008FF984
|cc cc cc cc| /
|cc cc cc cc| /
|0a 00 00 00| / a ebp-8 0x008FF990
|cc cc cc cc|/
| ebp | *ebp* 0x008ff998
| |\
| | __tmainCRTStartup
| |/
| | 高地址

忘记截图啦 跟上面main函数开辟空间是一样的

十四、压栈

00291779 push ebx
0029177A push esi
0029177B push edi

记不记得上面见过这些寄存器 所以操作是一样的
暂时不用理解这些寄存器
esp 自动指向最低地址处(栈顶)

低地址
|98 f9 8f 00| edi esp 0x008ff7c0
|23 10 29 00| esi
|00 70 75 00| ebx
| |\ 0x008ff7cc
| |
| |
| |
| |
| |
| | Add
| | /
| | /
| | /
| | /
| | /
| |/
|98 f9 8f 00| main-ebp ebp 0x008ff898
|f7 18 29 00| call的下一条指令 0x008FF89C
|0a 00 00 00| ecx(a) 0x008ff8a0
|14 00 00 00| eax(b) 0x008ff8a4
| edi | 0x008ff8a8
| esi |
| ebx |
|cc cc cc cc|
|00 00 00 00| \ c ebp-20h 0x008FF978
|cc cc cc cc| \
|cc cc cc cc| main
|14 00 00 00| /b ebp-14h 0x008FF984
|cc cc cc cc| /
|cc cc cc cc| /
|0a 00 00 00| / a ebp-8 0x008FF990
|cc cc cc cc|/
| ebp | *ebp* 0x008ff998
| |\
| | __tmainCRTStartup
| |/
| | 高地址

00291779 push ebx
0029177A push esi
0029177B push edi
压栈 ebx esi edi

请添加图片描述

十五、初始化Add函数

0029177C lea edi,[ebp-0Ch]
0029177F mov ecx,3
00291784 mov eax,0CCCCCCCCh
00291789 rep stos dword ptr es:[edi]

很熟悉有没有 如果你没记住 没关系我们再讲一遍
.
[ebp-0Ch]这么些空间放在edi
3存放在ecx
0CCCCCCCCh 存放在eax
ebp(栈底指针)向下ecx(3)个位置初始化成eax(cc cc cc cc)的值
.
说人话就是 将Add函数3个空间初始化为cc cc cc cc
前三句是存储 ,最后一局执行

请添加图片描述

低地址
|98 f9 8f 00| edi esp 0x008ff7c0
|23 10 29 00| esi
|00 70 75 00| ebx
| |\ 0x008ff7cc
| |
| |
| |
| |
| |
| | Add
| | /
| | /
| | /
|cc cc cc cc| /
|cc cc cc cc| /
|cc cc cc cc|/
|98 f9 8f 00| main-ebp ebp 0x008ff898
|f7 18 29 00| call的下一条指令 0x008FF89C
|0a 00 00 00| ecx(a) 0x008ff8a0
|14 00 00 00| eax(b) 0x008ff8a4
| edi | 0x008ff8a8
| esi |
| ebx |
|cc cc cc cc|
|00 00 00 00| \ c ebp-20h 0x008FF978
|cc cc cc cc| \
|cc cc cc cc| main
|14 00 00 00| /b ebp-14h 0x008FF984
|cc cc cc cc| /
|cc cc cc cc| /
|0a 00 00 00| / a ebp-8 0x008FF990
|cc cc cc cc|/
| ebp | *ebp* 0x008ff998
| |\
| | __tmainCRTStartup
| |/
| | 高地址



回顾一下Add函数内部的代码

int Add(int x, int y)
{
int z = 0;
z = x + y;
return z;
}


十六、函数内创建z并赋值0

int z = 0;
00291795 mov dword ptr [ebp-8],0

0放在[ebp-8]的位置上
此时vs2019可能跳转了 暂时不用管 继续F11 跳回去

低地址
|98 f9 8f 00| edi esp 0x008ff7c0
|23 10 29 00| esi
|00 70 75 00| ebx
| |\ 0x008ff7cc
| |
| |
| |
| |
| |
| | Add
| | /
| | /
| | /
|cc cc cc cc| /
|00 00 00 00| / z (ebp-8) 0x008FF890
|cc cc cc cc|/
|98 f9 8f 00| main-ebp ebp 0x008ff898
|f7 18 29 00| call的下一条指令 0x008FF89C
|0a 00 00 00| ecx(a) ebp+8 0x008ff8a0 |14 00 00 00| eax(b) ebp+c 0x008ff8a4
| edi | 0x008ff8a8
| esi |
| ebx |
|cc cc cc cc|
|00 00 00 00| \ c ebp-20h 0x008FF978
|cc cc cc cc| \
|cc cc cc cc| main
|14 00 00 00| /b ebp-14h 0x008FF984
|cc cc cc cc| /
|cc cc cc cc| /
|0a 00 00 00| / a ebp-8 0x008FF990
|cc cc cc cc|/
| ebp | *ebp* 0x008ff998
| |\
| | __tmainCRTStartup
| |/
| | 高地址

int z = 0;
00291795 mov dword ptr [ebp-8],0
创建z变量赋值为0
此时vs2019可能跳转了 暂时不用管 继续F11 跳回去

请添加图片描述

十七、函数内计算z = a+b

z = x + y;
0029179C mov eax,dword ptr [ebp+8]
0029179F add eax,dword ptr [ebp+0Ch]
002917A2 mov dword ptr [ebp-8],eax

读取ebp+8的值赋给eax eax = 10
ebp+0ch的值累加到eax eax = 10+20
eax的值 赋值给ebp-8的位置 z = 30
.
1e十六进制转换为十进制等于30

低地址
|98 f9 8f 00| edi esp 0x008ff7c0
|23 10 29 00| esi
|00 70 75 00| ebx
| |\ 0x008ff7cc
| |
| |
| |
| |
| |
| | Add
| | /
| | /
| | /
|cc cc cc cc| /
|1e 00 00 00| / z (ebp-8) 0x008FF890
|cc cc cc cc|/
|98 f9 8f 00| main-ebp ebp 0x008ff898
|f7 18 29 00| call的下一条指令 0x008FF89C
|0a 00 00 00| ecx(a) ebp+8 0x008ff8a0 |14 00 00 00| eax(b) ebp+c 0x008ff8a4
| edi | 0x008ff8a8
| esi |
| ebx |
|cc cc cc cc|
|00 00 00 00| \ c ebp-20h 0x008FF978
|cc cc cc cc| \
|cc cc cc cc| main
|14 00 00 00| /b ebp-14h 0x008FF984
|cc cc cc cc| /
|cc cc cc cc| /
|0a 00 00 00| / a ebp-8 0x008FF990
|cc cc cc cc|/
| ebp | *ebp* 0x008ff998
| |\
| | __tmainCRTStartup
| |/
| | 高地址

请添加图片描述

十八、将返z的值储到寄存器、然后弹栈

return z;
002917A5 mov eax,dword ptr [ebp-8]

[ebp-8]位置上的值 存储到eax
eax是寄存器 ,寄存器不在栈中, 所以弹栈的时候不会销毁 能顺利将值带回去
.
这里我们将弹栈一起运行完成
esp自动向高地址移动

科普

栈区使用 ,先压栈 ,当用完的时候就会弹栈
弹栈后弹出的位置将不属于现在的程序
但是值时保留的,原则不能访
当这块空间没被再次使用时
但是越界访问的时候也能访问到这里的值
这让我想起了数据恢复技术

return z;
002917A5 mov eax,dword ptr [ebp-8]
函数即将返回 销毁 为了保存z
将z的值 保存到寄存器eax中
002917A8 pop edi
002917A9 pop esi
002917AA pop ebx
弹出 esi esi ebx

–|98 f9 8f 00| edi 0x008ff7c0
–|23 10 29 00| esi
–|00 70 75 00| ebx
| |\ esp 0x008ff7cc
| |
| |
| |
| |
| |
| | Add
| | /
| | /
| | /
|cc cc cc cc| /
|1e 00 00 00| / z (ebp-8) 0x008FF890
|cc cc cc cc|/
|98 f9 8f 00| main-ebp ebp 0x008ff898
|f7 18 29 00| call的下一条指令 0x008FF89C
|0a 00 00 00| ecx(a) ebp+8 0x008ff8a0 |14 00 00 00| eax(b) ebp+c 0x008ff8a4
| edi | 0x008ff8a8
| esi |
| ebx |
|cc cc cc cc|
|00 00 00 00| \ c ebp-20h 0x008FF978
|cc cc cc cc| \
|cc cc cc cc| main
|14 00 00 00| /b ebp-14h 0x008FF984

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Go语言工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Go语言全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img
img
img

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

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

如果你觉得这些内容对你有帮助,可以添加V获取:vip1024b (备注Go)
img

一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

|98 f9 8f 00| main-ebp ebp 0x008ff898
|f7 18 29 00| call的下一条指令 0x008FF89C
|0a 00 00 00| ecx(a) ebp+8 0x008ff8a0 |14 00 00 00| eax(b) ebp+c 0x008ff8a4
| edi | 0x008ff8a8
| esi |
| ebx |
|cc cc cc cc|
|00 00 00 00| \ c ebp-20h 0x008FF978
|cc cc cc cc| \
|cc cc cc cc| main
|14 00 00 00| /b ebp-14h 0x008FF984

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Go语言工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Go语言全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
[外链图片转存中…(img-oQK3QdD3-1712998260916)]
[外链图片转存中…(img-BDKLYdbC-1712998260917)]
[外链图片转存中…(img-9LaJ3RGi-1712998260918)]
[外链图片转存中…(img-QUnZcREn-1712998260918)]
[外链图片转存中…(img-zmGFLpOM-1712998260919)]

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

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

如果你觉得这些内容对你有帮助,可以添加V获取:vip1024b (备注Go)
[外链图片转存中…(img-olvedACL-1712998260919)]

一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

;