对于以下操作:
void fun()
{
int x = 1;
return;
}
int main()
{
int y = 2;
fun();
}
vs2015Pro生成汇编码部分如下,结合其来弄清楚函数调用与返回过程中寄存器与内存具体发生了什么
01211208 jmp fun (01211700h)
void fun()
{
01211700 push ebp
01211701 mov ebp,esp
01211703 sub esp,0CCh
01211709 push ebx
0121170A push esi
0121170B push edi
0121170C lea edi,[ebp-0CCh]
01211712 mov ecx,33h
01211717 mov eax,0CCCCCCCCh
0121171C rep stos dword ptr es:[edi]
int x = 1;
0121171E mov dword ptr [x],1
return;
}
01211725 pop edi
01211726 pop esi
01211727 pop ebx
01211728 mov esp,ebp
0121172A pop ebp
0121172B ret
int main()
{
0121174A push esi
0121174B push edi
0121174C lea edi,[ebp-0CCh]
01211752 mov ecx,33h
01211757 mov eax,0CCCCCCCCh
0121175C rep stos dword ptr es:[edi]
int y = 2;
0121175E mov dword ptr [y],2
fun();
01211765 call fun (01211208h)
}
0121176A xor eax,eax
0121176C pop edi
0121176D pop esi
0121176E pop ebx
0121176F add esp,0CCh
从指令call开始说起:
01211765 call fun (01211208h)
执行前之前
ebp 0x00AFFC90–帧指针
eip 0x01211765–计数器
esp 0x00AFFBB8–栈指针
内存:
0x00AFFBB4 8b 0e 8c b1 ?.??
0x00AFFBB8 46 10 21 01 F.!.
执行之后(相当于将下一条指令入栈,并且计数器跳转到相应的fun()的地址)
ebp 0x00AFFC90–帧指针
eip 0x01211208–计数器(01211208 jmp fun (01211700h) 这条指令)
esp 0x00AFFBB8–栈指针
并且内存变为
0x00AFFBB4 6a 17 21 01 j.!.这里是小端机,读出为 0121176A 恰为main函数中call后下一条指令地址
0x00AFFBB8 46 10 21 01 F.!.
之后01211700 push ebp
将帧指针入栈
内存:
0x00AFFBB0 90 fc af 00 ???.
0x00AFFBB4 6a 17 21 01 j.!.
0x00AFFBB8 46 10 21 01 F.!.
之后01211701 mov ebp,esp
将帧指针入栈的地址作为新的帧指针地址
ebp 0x00AFFBB0–帧指针(恰为存放main帧指针的地址)
eip 0x01211703–计数器
esp 0x00AFFBB8–栈指针
然后
01211703 sub esp,0CCh
预分配栈空间或者是用作保护(?这里有点不确定)
ebp 0x00AFFBB0–帧指针
eip 0x01211709–计数器
esp 0x00AFFAE4–栈指针
执行一段时间fun()后
0121171C rep stos dword ptr es:[edi]
似乎是在进行栈的保护工作
将不停地在内存中从小到大(即像退栈pop一样)不停地将内存中区域置为cc cc cc cc,直到帧指针处
最后
0121172A pop ebp
0121172B ret
弹出ebp,跳回main函数
从整个过程还可以看出:
我经过多次编译,main()函数与fun()函数的地址是一样的
但是每次分配的内存是不同的
想到现代计算机为了防止黑客入侵–在消息中插入可执行代码–这一机制导致的随机分配内存?