2013-10-06 113 views
0

我仍然在学习汇编语言和C语言,但现在我正试图理解编译器是如何工作的。我这里有一个简单的代码:调试C程序(int声明)

int sub() 
{ 
    return 0xBEEF; 
} 
main() 
{ 
    int a=10; 
    sub(); 
} 

现在我知道CPU已经是如何工作的,跳进框架和子程序等 什么,我不明白是程序“商店”的局部变量。在这种情况下,在主框架?

这里是调试器主框架:在

0x080483f6 <+0>:  push %ebp 
    0x080483f7 <+1>:  mov %esp,%ebp 
    0x080483f9 <+3>:  sub $0x10,%esp 
=> 0x080483fc <+6>:  movl $0xa,-0x4(%ebp) 
    0x08048403 <+13>: call 0x80483ec <sub> 
    0x08048408 <+18>: leave 
    0x08048409 <+19>: ret 

我有 “INT A = 10;”这就是为什么偏移量6有箭头的原因。 因此,主要的功能开始别人推EBP唧唧歪歪等,然后我不明白这一点:

0x080483f9 <+3>:  sub $0x10,%esp 
=> 0x080483fc <+6>:  movl $0xa,-0x4(%ebp) 

为什么在ESP做子?是栈上的变量'a',堆栈指针的偏移量为-0x4?

只是为了清除这里的想法:D

在此先感谢!

+0

出于好奇,你使用gcc吗?如果是,哪个版本? – BlackBear

+0

gcc版本4.7.3(Ubuntu/Linaro 4.7.3-1ubuntu1) – int3

回答

2
0x080483f9 <+3>:  sub $0x10,%esp 

你会在每个函数中找到这样的指令。它的目的是创建一个合适大小的堆栈框架,以便该函数可以存储它的本地数据(请记住堆栈向后生长!)。
在这种情况下,堆栈帧有点太大。这是因为默认情况下,gcc(从2.96开始)将堆栈帧填充到16个字节的边界,以说明需要打包的128位向量对齐到16个字节的SSEx指令。 (参考文献here)。

=> 0x080483fc <+6>:  movl $0xa,-0x4(%ebp) 

此行正在将a初始化为正确的值(0xa = 10d)。本地总是被引用一个相对于ebp的偏移量,这标记了堆栈帧的开始(因此包含在ebp和esp之间)。

+0

'0x10'是十进制的'16'。那么为什么'sub'指令意味着堆栈帧的大小为4个字节? – us2012

+0

@ us2012:你完全正确,我忽略了这一点......而我只是休息一下;) – BlackBear

+0

好得多,+1 :)如果你对*为什么有一个解释*为什么堆栈框架似乎比要求的大,会很棒。 – us2012