GCC为x86生成的“push%ebp; movl%esp,%ebp”有什么用?

时间:2010-03-25 12:54:31

标签: gcc assembly x86

这两条指令对gcc为x86机器生成的汇编代码有什么影响:

push %ebp
movl %esp, %ebp

6 个答案:

答案 0 :(得分:59)

展开的解释是字面上的事实(尽管有一个小的方向错误),但并没有解释原因。

%ebp是堆栈帧的“基指针”。它是C运行时用于访问堆栈上的局部变量和参数的指针。这是GCC生成的一些典型的函数序言代码(准确地说是g ++)首先是C ++源代码。

// junk.c++
int addtwo(int a)
{
    int x = 2;

    return a + x;
}

这将生成以下汇编程序。

.file   "junk.c++"
    .text
.globl _Z6addtwoi
    .type   _Z6addtwoi, @function
_Z6addtwoi:
.LFB2:
    pushl   %ebp
.LCFI0:
    movl    %esp, %ebp
.LCFI1:
    subl    $16, %esp
.LCFI2:
    movl    $2, -4(%ebp)
    movl    -4(%ebp), %edx
    movl    8(%ebp), %eax
    addl    %edx, %eax
    leave
    ret
.LFE2:
    .size   _Z6addtwoi, .-_Z6addtwoi
    .ident  "GCC: (Ubuntu 4.3.3-5ubuntu4) 4.3.3"
    .section    .note.GNU-stack,"",@progbits

现在解释一下序言代码(.LCFI2:之前的所有内容),首先:

  1. pushl %ebp调用函数的堆栈帧存储在堆栈中。
  2. movl %esp, %ebp获取当前堆栈指针并将其用作调用函数的帧。
  3. subl $16, %esp为本地变量留出了空间。
  4. 现在您的功能已准备就绪。具有%ebp%寄存器的负偏移量的任何引用都是本地变量(在此示例中为x)。任何与%ebp%寄存器具有正偏移量的引用都是传入的参数。

    最后一个关注点是leave指令,它是一个x86汇编程序指令,用于恢复调用函数的堆栈帧。这通常会优化为C代码中更快的move %ebp %esppop %ebp%序列。但是,出于说明的目的,我根本没有进行任何优化编译。

答案 1 :(得分:9)

这是您在函数开头看到的典型代码。

它将EBP寄存器的内容保存在堆栈中,然后将当前堆栈指针的内容存储在EBP中。

在函数调用期间使用堆栈来存储本地参数。但是在函数中,堆栈指针可能会改变,因为值存储在堆栈中。

如果保存堆栈的原始值,可以通过EBP寄存器引用存储的参数,同时仍然可以使用(添加值)堆栈。

在功能结束时,您可能会看到命令

pop %ebp   ; restore original value 
ret        ; return 

答案 2 :(得分:7)

push %ebp

这将推动堆栈上的32位(扩展)基址指针寄存器,即堆栈指针(%esp)减去4,然后将%ebp的值复制到堆栈指针指向的位置。

movl %esp, %ebp

这将堆栈指针寄存器复制到基址指针寄存器。

将堆栈指针复制到基指针的目的是创建堆栈帧,即堆栈中子程序可以存储本地数据的区域。子程序中的代码将使用基指针来引用数据。

答案 3 :(得分:2)

这是所谓的function prolog

的一部分

它保存当函数结束时将要检索的当前基指针,并将新的ebp设置为新帧的开头。

答案 4 :(得分:1)

我还认为重要的是要注意经常在之后 push %ebpmovl %esp, %ebp 程序集将包含push %ebxpush %edx。这些是寄存器%ebx%edx的调用者保存。在例程调用结束时,寄存器将以其原始值恢复。

此外 - %ebx, %esi, %edi都是被调用者保存寄存器。因此,如果你想覆盖它们,你需要先保存它们,然后恢复它们。

答案 5 :(得分:0)

这段代码为您的程序设置了堆栈
在x86中,堆栈信息由两个寄存器保存。


    Base pointer (bp): Holds starting address of the stack
    Stack pointer (sp): Holds the address in which next value will be stored

这些寄存器在不同模式下有不同的名称:


                            Base pointer           Stack pointer
    16 bit real mode:       bp                     sp
    32 bit protected mode:  ebp(%ebp)              esp(%esp)
    64 bit mode:            rbp                    rsp

设置堆栈时,堆栈指针和基址指针在开头就会得到相同的地址。

现在解释一下你的代码,

Base pointer           Stack pointer

此代码将当前堆栈地址压入堆栈,以便该函数可以退出"退出"或"返回"正确。


    push %ebp

此代码为您的功能设置堆栈。

有关详细信息,请参阅此question

希望这有帮助!