2013-02-27 59 views
3

为了更好地理解二进制文件,我准备了一个小型的C++示例,并使用gdb进行反汇编并查找机器代码。通过创建本地变量减少堆栈指针

main()函数调用函数func()

int func(void) 
{ 
    int a; 
    int b; 
    int c; 
    int d; 
    d = 4; 
    c = 3; 
    b = 2; 
    a = 1; 
    return 0; 
} 

编译该项目使用g ++保持的调试信息。接下来的gdb用于反汇编源代码。我得到了func()样子:

0x00000000004004cc <+0>: push %rbp 
0x00000000004004cd <+1>: mov %rsp,%rbp 
0x00000000004004d0 <+4>: movl $0x4,-0x10(%rbp) 
0x00000000004004d7 <+11>: movl $0x3,-0xc(%rbp) 
0x00000000004004de <+18>: movl $0x2,-0x8(%rbp) 
0x00000000004004e5 <+25>: movl $0x1,-0x4(%rbp) 
0x00000000004004ec <+32>: mov $0x0,%eax 
0x00000000004004f1 <+37>: pop %rbp 
0x00000000004004f2 <+38>: retq 

现在我的问题是,我想到的是,堆栈指针应为16个字节移动到降低相对于基指针的地址,因为每个整数需要4个字节。但它看起来像是将值放在堆栈上而不移动堆栈指针。

我有什么不明白的地方?这是编译器的问题还是汇编器忽略了一些行?

最好的问候,
前功尽弃

+0

一些编译器不会做任何事情,但返回0. – QuentinUK 2013-02-27 12:54:42

+0

你尝试用'-O3'编译吗? – Walter 2013-02-27 13:00:50

+0

我总觉得你对“指令指针”的理解与我的不符。 – PlasmaHH 2013-02-27 13:03:47

回答

4

绝对没有你的编译器的问题。编译器可以自由选择如何编译你的代码,并选择不修改堆栈指针。没有必要这样做,因为你的函数没有调用任何其他函数。如果它确实调用了另一个函数,那么它将需要创建另一个堆栈帧,以便被调用者不会跺脚调用者的堆栈帧。

作为一般规则,您应该避免试图对编译器如何编译代码做任何假设。例如,你的编译器完全可以自由地消除你的函数体。

+0

谢谢,正是这一点。在调用一个额外的功能后,一切看起来都如预期的那样 – NouGHt 2013-02-27 13:00:17

+2

@Nought:一切都如预期。基本指针('%rbp')被存储在堆栈顶部以供稍后恢复。 '%rbp'然后将堆栈的旧顶部加载到它。然后使用相对于'%rbp'的地址访问堆栈,并设置所有本地变量。最后,基指针返回到它的原始值,'0'在'%eax'中返回。堆栈指针没有改变,因为代码中没有任何可能会破坏局部变量的东西,所以不需要通过将堆栈指针设置为某个值来将它们的位置传递给其他代码。 – Mankarse 2013-02-27 13:34:45