主函数和其他函数中局部变量的差异

时间:2014-12-23 09:32:26

标签: c gcc assembly gdb ubuntu-14.04

我很困惑。我在main函数中声明了一个变量,在另一个函数中声明了另一个变量。但是在gdb中,我发现程序通过main寄存器访问%esp函数中的变量,并通过%ebp寄存器访问另一个函数中的变量。不应该%ebp函数访问它吗?或者%espmain注册我不知道的隐藏规则?

/* source_file.c */
#include <stdio.h>

void localfunc(void)
{
    int local_in_func;
    local_in_func = 0x21;
    printf("local_in_func = %d\n", local_in_func);
}
int main(int argc, char **argv)
{
    int local_in_main;
    local_in_main = 0x97;
    printf("local_in_main = %d\n", local_in_main);
    return 0;
}

下面的反汇编代码:

(gdb) disassemble main
Dump of assembler code for function main:
   0x08048407 <+0>: push   %ebp
   0x08048408 <+1>: mov    %esp,%ebp
   0x0804840a <+3>: and    $0xfffffff0,%esp    ; visit local_in_main by esp
   0x0804840d <+6>: sub    $0x20,%esp
   0x08048410 <+9>: movl   $0x97,0x1c(%esp)
   0x08048418 <+17>:    mov    $0x8048524,%eax
   0x0804841d <+22>:    mov    0x1c(%esp),%edx
   0x08048421 <+26>:    mov    %edx,0x4(%esp)
   0x08048425 <+30>:    mov    %eax,(%esp)
   0x08048428 <+33>:    call   0x8048300 <printf@plt>
   0x0804842d <+38>:    mov    $0x0,%eax
   0x08048432 <+43>:    leave  
   0x08048433 <+44>:    ret    
End of assembler dump.

(gdb) disassemble localfunc
Dump of assembler code for function localfunc:
   0x080483e4 <+0>: push   %ebp
   0x080483e5 <+1>: mov    %esp,%ebp
   0x080483e7 <+3>: sub    $0x28,%esp
   0x080483ea <+6>: movl   $0x21,-0xc(%ebp)    ; visit local_in_func by ebp
   0x080483f1 <+13>:    mov    $0x8048510,%eax
   0x080483f6 <+18>:    mov    -0xc(%ebp),%edx
   0x080483f9 <+21>:    mov    %edx,0x4(%esp)
   0x080483fd <+25>:    mov    %eax,(%esp)
   0x08048400 <+28>:    call   0x8048300 <printf@plt>
   0x08048405 <+33>:    leave  
   0x08048406 <+34>:    ret    
End of assembler dump.

我的工具是:

  • 操作系统:ubuntu 12.04

  • 编译:gcc版本4.6.3(Ubuntu / Linaro 4.6.3-1ubuntu5)

  • debug:GNU gdb(Ubuntu / Linaro 7.4-2012.04-0ubuntu2.1)7.4-2012.04

1 个答案:

答案 0 :(得分:5)

传统上,%esp是堆栈指针,%ebp是'基本'指针,通常设置为堆栈指针位于函数开头的位置。

函数通过直接push或通过从%esp减去偏移量并访问旧%esp之间的空格的逻辑等效值将局部变量推送到堆栈中即%ebp)和新的%esp

这可以通过%esp的正偏移(例如0x1c(%esp)中的main)或%ebp的负偏移(例如{{}来完成在`local_function1)中的1}}。尽管编译器在多种方式之间进行选择以实现同样的事情,但是没有逻辑差异。

由于你的代码没有经过优化,我不会在选择中给予太多的重视,它可能是启发式的结果,在其他情况下有一些影响,但我不希望它在这里有很大的不同。