我有一个非常简单的程序,我的目标是研究编译器如何将值推送到不同的寄存器.但现在这种行为比预期的要复杂得多,至少在调试模式下如此.
这里发生了什么?
#include <cstdio>
struct A
{
int B;
A() : B(0) { }
};
int main()
{
A a;
A b(a);
printf("%d", b.B);
printf("%d", a.B);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
这就是Visual Studio中反汇编的样子:
int main()
{
01048210 push ebp
01048211 mov ebp,esp
01048213 sub esp,0D8h
01048219 push ebx
0104821A push esi
0104821B push edi
0104821C lea edi,[ebp-0D8h]
01048222 mov ecx,36h
01048227 mov eax,0CCCCCCCCh
0104822C rep stos dword ptr es:[edi]
A a;
0104822E lea ecx,[a]
01048231 call A::A (104678Ah)
A b(a);
01048236 mov eax,dword ptr [a]
01048239 mov dword ptr [b],eax
printf("%d", b.B);
0104823C mov eax,dword ptr [b]
0104823F push eax
01048240 push offset string "%d" (1093C6Ch)
01048245 call @ILT+3885(_printf) (1046F32h)
0104824A add esp,8
printf("%d", a.B);
0104824D mov eax,dword ptr [a]
01048250 push eax
01048251 push offset string "%d" (1093C6Ch)
01048256 call @ILT+3885(_printf) (1046F32h)
0104825B add esp,8
}
Run Code Online (Sandbox Code Playgroud)
在这个答案中解释了第一行,它们用于键入帧指针,以便可以生成好的堆栈跟踪.
但下一行令人困惑:为什么从esp中减去216(0D8h)?
main之后的这些行是什么,但在第一行代码之前A a;呢?
编辑:将运行时检查设置为默认值后,反汇编要小得多:
int main()
{
00247110 push ebp
00247111 mov ebp,esp
00247113 sub esp,48h
00247116 push ebx
00247117 push esi
00247118 push edi
A a;
Run Code Online (Sandbox Code Playgroud)
编辑2:在发布模式(/ Ox)中,a和b完全被优化掉,并且堆栈上根本没有分配内存:
int main()
{
A a;
A b(a);
printf("%d", b.B);
00B41000 push 0
00B41002 push 0B499A0h
00B41007 call printf (0B4102Dh)
printf("%d", a.B);
00B4100C push 0
00B4100E push 0B499A4h
00B41013 call printf (0B4102Dh)
00B41018 add esp,10h
return 0;
0127101B xor eax,eax
}
0127101D ret
Run Code Online (Sandbox Code Playgroud)
编辑3:这是使用的结果gcc -m32 -O3 -mpreferred-stack-boundary=2(感谢@CodyGray).
.LC0:
.string "%d"
Test():
push 0
push OFFSET FLAT:.LC0
call printf
pop eax
pop edx
push 0
push OFFSET FLAT:.LC0
call printf
pop ecx
pop eax
ret
Run Code Online (Sandbox Code Playgroud)
00CC8223 sub esp,0D8h
Run Code Online (Sandbox Code Playgroud)
为局部变量分配堆栈空间.
主要之后,但在第一条指令做之前,这些线是什么?
你指的是什么?