自学内容网 自学内容网

E40.【C语言】练习:有关栈帧的讨论(反汇编分析)

目录

1.题目

2.解

反汇编查看F1函数

3.改编

解:

反汇编分析

内存图


1.题目

下列代码中,F1的a和F2的b是否使用同一块栈帧空间?

#include <stdio.h>
void F1()
{
int a = 0;
printf("%p\n", &a);
}

void F2()
{
int b = 0;
printf("%p", &b);
}

int main()
{
F1();
F2();
}

2.解

程序运行时,VS先为main函数申请栈帧,执行到F1函数时再为其申请栈帧空间,但注意以下写法:

F1();
F2();

F1()运行完后,其栈帧被销毁,交换操作系统后,再执行F2()函数

反汇编查看F1函数

void F1()
{
 push        ebp  
 mov         ebp,esp  
 sub         esp,0D0h  
 push        ebx  
 push        esi  
 push        edi  
 lea         edi,[ebp-10h]  
 mov         ecx,4  
 mov         eax,0CCCCCCCCh  
 rep stos    dword ptr es:[edi]  
 mov         eax,dword ptr [__security_cookie (02FA040h)]  
 xor         eax,ebp  
 mov         dword ptr [ebp-4],eax  
 mov         ecx,offset _2D923C74_FileName@c (02FC009h)  
 call        @__CheckForDebuggerJustMyCode@4 (02F1334h)  
 nop  
int a = 0;
 mov         dword ptr [a],0  
printf("%p\n", &a);
 lea         eax,[a]  
 push        eax  
 push        offset string "%p\n" (02F7B30h)  
 call        _printf (02F10DCh)  
 add         esp,8  
}
 push        edx  
 mov         ecx,ebp  
 push        eax  
 lea         edx,ds:[2F20F8h]  
 call        @_RTC_CheckStackVars@8 (02F11F4h)  
 pop         eax  
 pop         edx  
 pop         edi  
 pop         esi  
 pop         ebx  
 mov         ecx,dword ptr [ebp-4]  
 xor         ecx,ebp  
 call        @__security_check_cookie@4 (02F1159h)  
 add         esp,0D0h  
 cmp         ebp,esp  
 call        __RTC_CheckEsp (02F1258h)  
 mov         esp,ebp  
 pop         ebp  
 ret  

注意到最后两行:  pop         ebpret(返回),之后交还操作系统

VS再为F2申请栈帧空间,用的空间是原来为F1申请的地方(空间可以重复利用),也就有了下面的结果,a与b存储的地址相同

3.改编

修改代码后,F1的a和F2的b是否使用同一块栈帧空间?

#include <stdio.h>
void F2();
void F1()
{
int a = 0;
printf("%p\n", &a);
F2();
}

void F2()
{
int b = 0;
printf("%p", &b);
}

int main()
{
F1();
}

解:

显然改成了嵌套调用,在F1()的内部调用F2(),导致F1()函数在F2()执行完之前无法返回

反汇编分析

void F1()
{
 push        ebp  
 mov         ebp,esp  
 sub         esp,0D0h  
 push        ebx  
 push        esi  
 push        edi  
 lea         edi,[ebp-10h]  
 mov         ecx,4  
 mov         eax,0CCCCCCCCh  
 rep stos    dword ptr es:[edi]  
 mov         eax,dword ptr [__security_cookie (0F7A040h)]  
 xor         eax,ebp  
 mov         dword ptr [ebp-4],eax  
 mov         ecx,offset _2D923C74_FileName@c (0F7C009h)  
 call        @__CheckForDebuggerJustMyCode@4 (0F71334h)  
 nop  
int a = 0;
 mov         dword ptr [a],0  
printf("%p\n", &a);
 lea         eax,[a]  
 push        eax  
 push        offset string "%p\n" (0F77B30h)  
 call        _printf (0F710DCh)  
 add         esp,8  
F2();
 call        _F2 (0F71037h)  
 nop  
}
 push        edx  
 mov         ecx,ebp  
 push        eax  
 lea         edx,ds:[0F747D0h]  
 call        @_RTC_CheckStackVars@8 (0F711F4h)  
 pop         eax  
 pop         edx  
 pop         edi  
 pop         esi  
 pop         ebx  
 mov         ecx,dword ptr [ebp-4]  
 xor         ecx,ebp  
 call        @__security_check_cookie@4 (0F71159h)  
 add         esp,0D0h  
 cmp         ebp,esp  
 call        __RTC_CheckEsp (0F71258h)  
 mov         esp,ebp  
 pop         ebp  
 ret 

尽管在F1函数的最后有ret返回指令,但是call        _F2 (0F71037h)指令在前,导致先去执行F2()函数,待F2结束后再执行call后的指令

再看看F2函数的反汇编指令:

void F2()
{
 push        ebp  
 mov         ebp,esp  
 sub         esp,0D0h  
 push        ebx  
 push        esi  
 push        edi  
 lea         edi,[ebp-10h]  
 mov         ecx,4  
 mov         eax,0CCCCCCCCh  
 rep stos    dword ptr es:[edi]  
 mov         eax,dword ptr [__security_cookie (0F7A040h)]  
 xor         eax,ebp  
 mov         dword ptr [ebp-4],eax  
 mov         ecx,offset _2D923C74_FileName@c (0F7C009h)  
 call        @__CheckForDebuggerJustMyCode@4 (0F71334h)  
 nop  
int b = 0;
 mov         dword ptr [b],0  
printf("%p", &b);
 lea         eax,[b]  
 push        eax  
 push        offset string "%p" (0F77BD0h)  
 call        _printf (0F710DCh)  
 add         esp,8  
}
 push        edx  
 mov         ecx,ebp  
 push        eax  
 lea         edx,ds:[0F742A8h]  
 call        @_RTC_CheckStackVars@8 (0F711F4h)  
 pop         eax  
 pop         edx  
 pop         edi  
 pop         esi  
 pop         ebx  
 mov         ecx,dword ptr [ebp-4]  
 xor         ecx,ebp  
 call        @__security_check_cookie@4 (0F71159h)  
 add         esp,0D0h  
 cmp         ebp,esp  
 call        __RTC_CheckEsp (0F71258h)  
 mov         esp,ebp  
 pop         ebp  
 ret 

注意到最后的ret返回指令,其返回后,来到了call        _F2 (0F71037h)下面的nop空指令

此后才能对F1()函数返回,也就有了下面的结果,a与b存储的地址不一样

内存图

如果画张内存图来表示main,F1,F2这三个函数


原文地址:https://blog.csdn.net/2401_85828611/article/details/142894263

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!