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:此空间是否用于除局部变量之外的其他内容?如果是,为什么?
#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分配
评论
我建议您发布单独的问题,以上每个子问题都应发布一个。对于每个问题,请发布函数的源代码和函数的完整反汇编。这将使您更容易自信地做出回应,而不是猜测。@JasonGeffner我发布了该函数的C源代码。这非常简单。我认为这四个子问题非常相关。我看不出发布四个具有相同初始描述且标题非常相似的不同问题的意义。
肯定有一些有趣的“优化”……例如,请注意,反汇编的VC ++代码将始终返回0,而不是c的值。
MSVC在调试模式下使用0xCC初始化未初始化的内存。这有助于更轻松地调试一些问题
您应该将MSVC项目更改为x64。比较MSVC 32位代码和GCC 64位代码是没有意义的