簡體   English   中英

x86_64匯編程序中RBP寄存器的用途是什么?

[英]What is the purpose of the RBP register in x86_64 assembler?

所以我正在嘗試學習一點裝配,因為我需要它用於計算機體系結構類。 我寫了一些程序,比如打印Fibonacci序列。

我認識到每當我編寫一個函數時,我都會使用這三行(正如我從gcc生成的匯編代碼與它的C等價物進行比較所學到的):

pushq   %rbp
movq    %rsp, %rbp
subq    $16, %rsp

我有2個問題:

  1. 首先,為什么我需要使用%rbp 使用%rsp是不是更簡單,因為它的內容被移動到第二行的%rbp
  2. 為什么我必須從%rsp減去任何東西? 我的意思是它並不總是16 ,當我printf 7或8個變量時,我會減去2428

我在虛擬機(4 GB RAM),Intel 64位處理器上使用Manjaro 64位

rbp是x86_64上的幀指針。 在生成的代碼中,它獲取堆棧指針( rsp )的快照,以便在對rsp調整時(即為局部變量保留空間或pushpush送到堆棧),仍可從本地變量和函數參數訪問與rbp的恆定偏移量。

許多編譯器提供幀指針省略作為優化選項; 這將使生成的匯編代碼相對於rsp訪問變量,並將rbp釋放為另一個用於函數的通用寄存器。

在GCC的情況下,我猜測你正在使用AT&T匯編語法,那個開關是-fomit-frame-pointer 嘗試使用該開關編譯代碼並查看您獲得的匯編代碼。 您可能會注意到,當訪問相對於rsp而不是rbp值時,指針的偏移量會在整個函數中發生變化。

Linux使用System V ABI for x86-64(AMD64)架構; 有關詳細信息 ,請參閱OSDev Wiki上的System V ABI

這意味着堆棧會逐漸減少 ; 較小的地址在堆棧中“更高”。 典型的C函數編譯為

        pushq   %rbp        ; Save address of previous stack frame
        movq    %rsp, %rbp  ; Address of current stack frame
        subq    $16, %rsp   ; Reserve 16 bytes for local variables

        ; ... function ...

        movq    %rbp, %rsp  ; \ equivalent to the
        popq    %rbp        ; / 'leave' instruction
        ret

為局部變量保留的內存量始終是16個字節的倍數,以使堆棧保持對齊為16個字節。 如果局部變量不需要堆棧空間,則沒有subq $16, %rsp或類似指令。

(注意,推送到堆棧的返回地址和前面的%rbp都是8個字節,總共16個字節。)

%rbp指向當前堆棧幀, %rsp指向堆棧頂部。 因為編譯器知道函數內任何點上%rbp%rsp之間的差異,所以可以自由地使用其中一個作為局部變量的基礎。

堆棧框架只是本地函數的操場:當前函數使用的堆棧區域。

每當使用優化時,當前版本的GCC都會禁用堆棧幀。 這是有道理的,因為對於用C編寫的程序,堆棧幀對調試最有用,但不是很多。 (但是,您可以使用例如-O2 -fno-omit-frame-pointer來保持堆棧幀,否則啟用優化。)

雖然相同的ABI適用於所有二進制文件,但無論它們是用什么語言編寫的,某些其他語言都需要堆棧幀來“展開”(例如,向當前函數的祖先調用者“拋出異常”); 即,“展開”堆棧幀,可以中止一個或多個函數並將控制傳遞給某個祖先函數,而不會在堆棧上留下不需要的東西。

當省略堆棧幀 - 用於GCC的-fomit-frame-pointer ,函數實現基本上改變為

        subq    $8, %rsp    ; Re-align stack frame, and
                            ; reserve memory for local variables

        ; ... function ...

        addq    $8, %rsp
        ret

因為沒有堆棧幀( %rbp用於其他目的,並且它的值永遠不會被推送到堆棧),所以每個函數調用只將返回地址推送到堆棧,這是一個8字節的數量,所以我們需要減去來自%rsp 8來保持它是16的倍數。(通常,從%rsp減去並添加到%rsp是8的奇數倍。)

函數參數通常在寄存器中傳遞。 有關詳細信息,請參閱本答案開頭的ABI鏈接,但簡而言之,整數類型和指針在寄存器%rdi%rsi%rdx%rcx%r8%r9 %rcx ,並帶有浮點參數%xmm0%xmm7寄存器。

在某些情況下,你會看到rep ret而不是rep 不要混淆:在rep ret意味着同樣的事情為ret ; rep前綴雖然通常與字符串指令(重復指令)一起使用,但在應用於ret指令時不執行任何操作。 只是某些AMD處理器的分支預測器不喜歡跳轉到ret指令,推薦的解決方法是在那里使用rep ret

最后,我省略了堆棧頂部上方的紅色區域 (地址小於%rsp的128個字節)。 這是因為它對於典型的函數並不真正有用:在普通的has-stack-frame情況下,你需要你的本地東西在堆棧框架內,以便進行調試。 在omit-stack-frame的情況下,堆棧對齊要求已經意味着我們需要從%rsp減去8,因此包含該減法中局部變量所需的內存不需要任何成本。

暫無
暫無

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

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