【问题标题】:The difference of local variables in main and other functionmain和其他函数中局部变量的区别
【发布时间】:2014-12-23 09:32:25
【问题描述】:

我很困惑。我在main 函数中声明了一个变量,在另一个函数中声明了另一个变量。但是在gdb中,我发现程序通过%esp寄存器访问main函数中的变量,通过%ebp寄存器访问另一个函数中的变量。 %ebp函数不应该全部访问吗?还是%esp访问注册main不知道是什么潜规则?

/* 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)

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

【问题讨论】:

  • main() 的代码还有一个额外的and $0xfffffff0,%esp,这是为什么呢?
  • 试试-O。您的功能不等效,因为一个返回的东西。 gcc 对堆栈对齐所做的假设可能与 main 不同。
  • 和 $0xfffffff0,%esp 对齐堆栈。
  • 我用-O试试,把main改成void main(void),这和其他功能一样。而我得到的结果是,在both函数中,程序通过%esp寄存器访问了局部变量。

标签: c gcc assembly gdb ubuntu-14.04


【解决方案1】:

通常,%esp 是堆栈指针,%ebp 是“基”指针,通常设置为堆栈指针在函数开头的位置。

函数通过使用直接push 或通过从%esp 中减去偏移量并访问旧%esp(即%ebp)和新的%esp

这可以通过与%esp 的正偏移量(例如通过main 中的0x1c(%esp))或通过从%ebp 的负偏移量(例如`local_function1 中的-0xc(%ebp))来完成。尽管编译器有许多性能启发式方法可以在实现同一目标的多种方式之间进行选择,但这并没有逻辑上的区别。

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

【讨论】:

  • 而在 x86 上,由于“红色区域”,某些函数甚至不需要移动 sp(重点是:编译器不需要遵守教科书的“规则”)。
  • 您好,感谢您的回复。我基本了解您的回答,但我对“红色区域”一无所知,稍后我会搜索它。我的问题是我通过嵌入的asm 代码更改了主函数中的%esp,这将导致我在main 函数中丢失了我的局部变量。那么我该如何解决这个问题呢?非常感谢!
  • 有不同的方法可以做到这一点。一种是使用扩展的内联汇编语法,它允许您在汇编中使用变量...请参见此处:gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html
  • 对不起,我没有说清楚。我的意思是我通过C代码在main函数中声明一个局部变量,然后我通过内联asm代码更改%esp寄存器,然后我尝试使用C代码访问局部变量我声明了,但是程序通过%esp寄存器访问局部变量,所以在我更改之前,例如变量位于-0xc(%esp),但现在0xc(%esp)不是变量的位置,因为我更改了%esp。我不是以英语为母语的人,也许我的描述不清楚,对此感到抱歉。衷心感谢您的回复。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-07-26
  • 2013-01-06
  • 2020-11-03
  • 1970-01-01
  • 1970-01-01
  • 2022-06-16
  • 2016-01-17
相关资源
最近更新 更多