簡體   English   中英

“ push%ebp;”的用法是什么? movl%esp,%ebp”由GCC為x86生成?

[英]What is the use of “push %ebp; movl %esp, %ebp” generated by GCC for x86?

這兩條指令在gcc為x86機器生成的匯編代碼中產生了什么影響:

push %ebp
movl %esp, %ebp

unwind的解釋是字面上的事實(盡管有一個較小的方向性錯誤),但沒有解釋原因。

%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為局部變量留出空間。

現在,您的功能已准備就緒,可以開始業務了。 %ebp%寄存器的偏移量為負的任何引用都是您的局部變量(在本示例中為x )。 任何從%ebp%寄存器偏移正值的引用都是您傳入的參數。

最后的關注點是leave指令,它是x86匯編程序指令,它負責恢復調用函數的堆棧幀。 通常,這可以優化為在C代碼中更快地move %ebp %esppop %ebp%序列。 但是,出於說明目的,我根本沒有進行任何優化。

這是在函數開始時看到的典型代碼。

它將EBP寄存器的內容保存在堆棧中,然后將當前堆棧指針的內容存儲在EBP中。

在函數調用期間使用堆棧來存儲局部參數。 但是在函數中,堆棧指針可能會更改,因為值存儲在堆棧中。

如果保存堆棧的原始值,則可以通過EBP寄存器引用存儲的參數,而您仍然可以使用堆棧(向堆棧中添加值)。

在函數的最后,您可能會看到命令

pop %ebp   ; restore original value 
ret        ; return 
push %ebp

這會將32位(擴展的)基本指針寄存器壓入堆棧,即堆棧指針(%esp)減四,然后將%ebp的值復制到堆棧指針指向的位置。

movl %esp, %ebp

這會將堆棧指針寄存器復制到基本指針寄存器。

將堆棧指針復制到基本指針的目的是創建一個堆棧框架,即堆棧上子程序可以存儲本地數據的區域。 子例程中的代碼將使用基本指針來引用數據。

它是所謂的函數prolog的一部分

它保存函數結束時要檢索的當前基本指針,並將新的ebp設置為新幀的開頭。

我還認為必須注意的是,通常在push %ebpmovl %esp, %ebp ,程序集push %ebxpush %edx 這些是寄存器%ebx%edx調用者保存。 在例行調用結束時,寄存器將恢復為其原始值。

另外- %ebx, %esi, %edi都是被調用者保存寄存器。 因此,如果要覆蓋它們,則需要先保存它們,然后再還原它們。

這段代碼為您的程序設置了堆棧。

在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

設置堆棧時,堆棧指針和基址指針在開始時會獲得相同的地址。

現在解釋一下您的代碼,


    push %ebp

此代碼將當前堆棧地址壓入堆棧,以便函數可以正確“退出”或“返回”。


    movl %esp, %ebp

這段代碼為您的函數設置了堆棧。

有關更多信息,請參閱此問題

希望有幫助!

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM