2015-10-23 25 views
1

我想了解C編譯器在編譯爲彙編時將執行什麼操作。我編譯到彙編代碼是這樣的:編譯器在這個彙編代碼中做了什麼?

void main() { 
    int x = 10; 
    int y = 10; 
    int a = x + y; 
} 

將會產生以下組件:

   .Ltext0: 
        .globl main 
       main: 
       .LFB0: 
0000 55    pushq %rbp 
0001 4889E5   movq %rsp, %rbp 
0004 C745F40A  movl $10, -12(%rbp) 
000b C745F80A  movl $10, -8(%rbp) 
0012 8B45F8   movl -8(%rbp), %eax 
0015 8B55F4   movl -12(%rbp), %edx 
0018 01D0   addl %edx, %eax 
001a 8945FC   movl %eax, -4(%rbp) 
001d 5D    popq %rbp 
001e C3    ret 

但是我有一些很難理解尤其是在這個片段是怎麼回事。我瞭解所有的標籤和一些裝配。這是我認爲它的作用:

  • push rbp? - 這是一個堆棧框架還是什麼?
  • 設置堆棧指針指向基址指針? (即清除堆棧)
  • 將10移入堆棧?偏移量爲-12?爲什麼12,爲什麼是負面的?
  • 在-8代替-12在-8(4差異,也許字節或什麼?)
  • 移動值在-12移動10插入棧,雖然此時進入EAX
  • 移動值到EDX
  • add eax and edc
  • 將值從eax移入堆棧
  • pop rbp?函數堆棧幀結束可能嗎?
  • 從函數返回??

任何人都可以澄清這個組件的某些點,也許是編譯器具有推理在選擇-8,-12,爲什麼選擇EAX和EDC在其他一些寄存器,它爲什麼push和pop RBP等?

+2

對於你的每一個問題的答案是「閱讀關於堆棧幀的好介紹文本」 –

+0

@ WumpusQ.Wumbley哈哈,好吧我會這麼做的! – mosmo

回答

3

push rbp? - 這是一個堆棧框架還是什麼?

是。編譯器爲局部變量創建一個堆棧幀。 push %rbp/movq %rsp, %rbp是這樣做的標準方法。它允許輕鬆訪問局部變量。

將10移入堆棧?偏移量爲-12?爲什麼12,爲什麼是負面的?

在這種情況下,編譯器選擇使用的堆疊的4個字節(int尺寸)部分從-12(%rbp)-9(%rbp)至用於可變x

一旦創建堆棧幀,您可以訪問負偏移局部變量和函數參數正偏移:

------------------------------------------------------ 
         | R | 
    New stack (locals) | B | Old stack (parameters) 
         | P | 
------------------------------------------------------ 
         ^
          RBP is updated to point here as well so you get negative offsets (to the left) for locals and positive offsets (to the right) for parameters. 

注意,由於存儲的RBP也佔用空間,以及返回該函數的地址,您需要將16個字節添加到任何參數偏移量。 (對於32位系統,8字節)

通常,在使用本地變量進行任何工作之前,必須更新RSP,如下所示:subq $12, %rsp。離開功能時,請使用addq $12, %rspleave。本示例更新堆棧指針以顯示我們在堆棧上使用了12個字節。當你完成它們時,你只需恢復堆棧指針。在你的例子中,雖然沒有這個需要,因爲這個函數沒有其他地方變量用於堆棧。

在-8代替-12

一旦再次移動10插入堆,儘管此時,引用一個局部變量,但此時,編譯器選擇了4字節部分開始在-8(%rbp)-5(%rbp)變量y

在這種情況下,pop %rbp棧在函數的結束,恢復到什麼是進入前:

------------------------------------------------------ 
         | R | 
    New stack (locals) | B | Old stack (parameters) 
         | P | 
------------------------------------------------------ 
         ^
          RSP points here, so a `pop %rbp` will restore both RSP and RBP 

編譯器可能會嘗試使用EAXEDX首先是因爲EAX是專爲數學操作和EDX專爲通用數據操作而設計。你經常會發現他們在操作中配對。

+1

編譯器實際上不應該在它爲本地使用EBP負偏移之前實際更新SP?還是僅僅因爲該方法不調用任何子函數而優化掉了它? – PMF

+0

輝煌,謝謝! – mosmo

0

要理解由編譯器生成的程序集,您必須瞭解堆棧幀。 SP是堆棧指針,BP指向當前堆棧幀,它用於尋址局部變量(因此將值「10」移動到[bp-12]和[bp-8]。然後將其加載到第一個可用註冊一個加法(在這種情況下是ax和dx)並執行加法。最後,它恢復舊堆棧並返回。