# 包含呼叫函式的範例

我們來看一個比較複雜的範例，看看有呼叫函式的程式會被編成什麼樣的組合語言指令。

呼叫函式和一般的跳躍不同，在呼叫結束後必須回到原本呼叫的地方，原本執行中的位址被叫做「回傳位址」（return address）。如果說呼叫只會發生一次的話，隨便找一個暫存器存回傳位址就好了；但是函式呼叫可以一層一層呼叫下去，所以必須把回傳位址存在記憶體裡。實務上，回傳位址被存在記憶體中的堆疊（stack）裡。

堆疊，被實作成只能使用堆疊空間最上方位址所存的一個變數。而這個紀錄堆疊最上方的紀錄空間被稱為「堆疊指標」（stack pointer）。x86-64 中，為了方便寫呼叫函式的程式，提供了堆疊指標專用的暫存器，和使用這個暫存器的指令。往堆疊上堆資料的操作是「push」，而取出堆疊資料的操作是「pop」。

接下來我們來看看操作堆疊的範例。試想以下的C程式碼：

```c
int plus(int x, int y) {
  return x + y;
}

int main() {
  return plus(3, 4);
}
```

而底下是與這個C程式碼對應的組合語言指令：

```
.intel_syntax noprefix
.global plus, main

plus:
        add rsi, rdi
        mov rax, rsi
        ret

main:
        mov rdi, 3
        mov rsi, 4
        call plus
        ret
```

第一行是指定組合語言文法的指令。由`.global`開始的第二行，是指定`main`和`plus`這兩個可見於程式全體（program scope），非檔案範圍（file scope）的函式的組合語言指令。（譯註：有關 program scope 和 file scope，請參考C語言的相關資料。）現階段可以暫時忽略沒有關係。

首先來看`main`。C程式看起來就是在`main`呼叫了`plus`函式；在組合語言部分，默認第一引數（argument）放在 RDI 暫存器、第二引數放在 RSI 暫存器，`main`的最初兩行便是設定這兩個暫存器的值。

`call`就是呼叫函式的指令。具體來說`call`做了下列兩件事情：

* 把`call`的下一行指令的位址 push 進堆疊中
* 跳到`call`的引數所給的位址

於是，`call`實行時，CPU 便會開始執行`plus`。

接下來看`plus`。`plus`函式包含有三個指令。

`add`是加法的指令。在這裡是把 RSI 和 RDI 兩個暫存器內的值相加，再寫回 RSI 暫存器中。x86-64 的整數運算指令通常都只接受兩個暫存器，所以必須要把運算結果寫回其中一個暫存器中。

函式的回傳值則被寫進 RAX 暫存器。由於我們想要的是加法的結果，所以必須把 RSI 暫存器的值複製到 RAX 暫存器，這邊用來複製的指令是`mov`指令。`mov`是 move 的省略，但實際上並不是移動而是複製資料的指令。

`plus`函式的最後，執行`ret`指令從函式中回傳。`ret`指令具體來說做的是下列兩件事：

* 從堆疊中 pop 一個位址出來
* 跳到該位址

也就是說，`ret`指令是跳回執行`call`的地方，並從該處開始繼續執行的指令。`call`和`ret`是成對設計的指令。

從`plus`傳回之後就是`main`裡的`ret`指令。從C程式看，`main`是把`plus`的回傳值直接傳回去。在這裡 RAX 裡放的是`plus`的回傳值，所以這裡`main`直接回傳，RAX 裡的值也就成了main的回傳值了。


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://koshizuow.gitbook.io/compilerbook/machine_code_assembler/c_assembly/kansuu_yobidashi.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
