为什么%esp会改变imexplitcitly?

时间:2017-05-24 08:21:11

标签: c assembly operating-system gdb

标题实际上是我的第二个问题。 当我学习CSAPP第2版第3章时出现了2个问题。有2个相对简单的文件。这是第一个:

    // code.c
    int accum = 0;

    int sum(int x, int y)
    {
         int     t = x + y;
         accum += t;
         return t;
    }

第二个:

    // main.c
    int main() {
         return sum(1, 3);
    }

我按照这本书使用gcc编译它们。为了得到一个32位程序,我添加了一个-m32选项(我的是64位Ubuntu):

   $ gcc -m32 -O1 -O prog code.c main.c

到目前为止事情很顺利。但是当我使用GDB对它进行反汇编时,它真的让我很困惑。我得到的结果与本书的内容相矛盾:

    (gdb) disas sum
    Dump of assembler code for function sum:
        0x080483ed <+0>:    mov    0x8(%esp),%eax
        0x080483f1 <+4>:    add    0x4(%esp),%eax
        0x080483f5 <+8>:    add    %eax,0x804a020
        0x080483fb <+14>:   ret    
    End of assembler dump.
    (gdb) disas main
    Dump of assembler code for function main:
        0x080483fc <+0>:    push   %ebp
        0x080483fd <+1>:    mov    %esp,%ebp
        0x080483ff <+3>:    and    $0xfffffff0,%esp
        0x08048402 <+6>:    sub    $0x10,%esp
        0x08048405 <+9>:    movl   $0x3,0x4(%esp)
        0x0804840d <+17>:   movl   $0x1,(%esp)
        0x08048414 <+24>:   call   0x80483ed <sum>
        0x08048419 <+29>:   leave  
        0x0804841a <+30>:   ret    
   End of assembler dump.

现在我的问题出现了:

  1. 在书中描述时,为什么在调用函数 sum 时没有保存%ebp或移动%esp?或者编译器内联 sum
  2. 价值3&amp; 1已经存储在M [%esp + 4]&amp; M [%esp],分别。在调用 sum 之后,没有指令改变存储在%esp中的值。但是在 sum 中,第一条指令检索M [%esp + 8],实际上是3(我使用GDB设置断点并检查该值),而M [%esp + 4]存储价值1.怎么样?后来我设置了两个断点:

     (gdb) break *0x08048414
     (gdb) break sum
    
  3. 然后我发现存储在%esp中的值在这两个断点处是不同的:

         Breakpoint 6, 0x08048414 in main ()
         (gdb) print $esp
         $8 = (void *) 0xffffd020
         (gdb) continue
         Continuing.
    
         Breakpoint 5, 0x080483ed in sum ()
         (gdb) print $esp
         $9 = (void *) 0xffffd01c
    

    为什么会发生这种情况?

1 个答案:

答案 0 :(得分:1)

  

为什么在本书描述的时候调用函数sum时没有任何保存%ebp或移动%esp?

您可能已启用省略帧指针的选项,很可能使用-Ox编译器选项。您可以强制GCC使用-fno-omit-frame-pointer GCC命令行参数保留它:

https://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html#index-O

  

但总和之内,第一条指令检索M [%esp + 8],实际上是3,而M [%esp + 4]存储值1.为什么?

调用指令将eip寄存器推送到堆栈并移动esp。您在32位模式下编译它,因此偏移量为4个字节。