我在Visual Studio 2010中调试了一个简单的x86-64程序,我注意到main函数的序言与同一C程序的GNU GCC编译版本不同。 main函数的C代码:

int main() {
  int a,b,c;
  a=1;
  b=2;
  c=proc(a,b);
  return c;
}


VC ++版本的main函数序言的Visual Studio 2010反汇编为:

VC ++版本的其余功能代码为: :

01211410  push        ebp  
01211411  mov         ebp,esp  
01211413  sub         esp,0E4h  
01211419  push        ebx  
0121141A  push        esi  
0121141B  push        edi  
0121141C  lea         edi,[ebp-0E4h]  
01211422  mov         ecx,39h  
01211427  mov         eax,0CCCCCCCCh  
0121142C  rep stos    dword ptr es:[edi]


GCC版本的其余main功能代码是:

0081141E  mov         dword ptr [a],1  
00811425  mov         dword ptr [b],2  
0081142C  mov         eax,dword ptr [b]  
0081142F  push        eax  
00811430  mov         ecx,dword ptr [a]  
00811433  push        ecx  
00811434  call        proc (81114Fh)  
00811439  add         esp,8  
0081143C  mov         dword ptr [c],eax  
0081143F  mov         eax,dword ptr [c]  
00811442  pop         edi  
00811443  pop         esi  
00811444  pop         ebx  
00811445  add         esp,0E4h  
0081144B  cmp         ebp,esp  
0081144D  call        @ILT+300(__RTC_CheckEsp) (811131h)  
00811452  mov         esp,ebp  
00811454  pop         ebp  
00811455  ret 


main版本2.22.90.20120924给出了反汇编。

我意识到两个序言的前3条指令都执行以下操作:删除堆栈框架)
旧堆栈框架的顶部应为出现新框架的EBP
为局部变量保留空间。该函数具有3个整数局部变量。

问题1:VC ++版本中的第4条指令的作用是什么?我看到它正在保存EBX,但是为什么呢?

对于VC ++版本序言的其余说明,我认为它用值objdump初始化39h双字。这是有道理的,因为0CCCCCCCCh

问题2:为什么将此空间初始化为39h * 4h = 0E4h值?问题3:为什么VC ++版本为3个局部变量分配0CCCCCCCCh字节?这个数字是随机的吗?如果不是,该如何计算?

问题4:此空间是否用于除局部变量之外的其他内容?如果是,为什么?

评论

我建议您发布单独的问题,以上每个子问题都应发布一个。对于每个问题,请发布函数的源代码和函数的完整反汇编。这将使您更容易自信地做出回应,而不是猜测。

@JasonGeffner我发布了该函数的C源代码。这非常简单。我认为这四个子问题非常相关。我看不出发布四个具有相同初始描述且标题非常相似的不同问题的意义。

肯定有一些有趣的“优化”……例如,请注意,反汇编的VC ++代码将始终返回0,而不是c的值。

MSVC在调试模式下使用0xCC初始化未初始化的内存。这有助于更轻松地调试一些问题

您应该将MSVC项目更改为x64。比较MSVC 32位代码和GCC 64位代码是没有意义的

#1 楼

堆栈上有多余的空间来支持“编辑并继续”功能,可以通过将/ Zl更改为/ Zi来消除。保存的ebx和将堆栈初始化为0xcc是由/ RTC运行时检查选项完成的。

SO上也有类似的问题。方式,显然是32位二进制。 x64 Windows调用约定使用RCX,RDX,R8和R9作为前4个整数/指针参数(而不是堆栈)。

评论


是。在x86_64中,没有办法推送ebp。 OP应该将项目更改为x86_64并查看

–phuclv
14年6月16日在13:12

#2 楼


不确定,也许这是“标准的”,以便编译器理所当然可以使用ebx(无需检查是否可以)。
您应该知道0x0CC是int 3,调试断点。可能是,如果您突然跳到未初始化的内存,则会得到int 3而不是A / V或类似异常。虽然只是一个猜测。没有提到的一件事是编译器标志。是调试版本吗?
不确定
不确定,请尝试关闭堆栈保护,看看是否仍然获得大的0x0E4分配