# 你所不知道的C語言:函式呼叫篇
contributed by < [`ofAlpaca`](https://github.com/ofAlpaca) >
###### tags: `CSIE5006` `Note`
### Nested function
* C 語言不支援 nested function,其目的為簡化編譯器設計。
```clike=
void f() {
// declaration of function g
void g();
g();
// once exit the function, function g()
// is out of scope.
}
```
---
### Process 和 C 程式的關聯
* Virtual Memory 與 C 語言角度的 memory: [source](http://www.study-area.org/cyril/opentools/opentools/x909.html) (注意 address 是降冪還是升冪)
* Process 角度的 Memeory : ([source](https://manybutfinite.com/post/anatomy-of-a-program-in-memory/))
* ==在 ELF 裡頭為 section, 進入到 memory 後則以 process 的 segment 去看。==
* 注意,這裡是 virtual memory address (VMA)! ([VMA 與 ELF 對應](https://www.jollen.org/blog/2007/01/process_vma.html))
* Stack : 由高位址長至低位址,儲存函式呼叫時個別 stack frame 的 local variables 與 return address 等。
* Heap : 由低位址長至高位址,動態記憶體配置。
* BSS segement: Block Started by Symbol ,尚未初始化的變數。
* Data segement : 已經被初始化後的變數。
* 在此宣告的變數會存在 **data segment** ,例如: `int content = 10` 。
* 但是宣告在此的 pointer 所指向的內容則不會,也就是說 `gonzo` 的內容 `God's own prototype` 會是放在 text segment 裡,只有 pointer 所存的**位址**會在 data segment 。
* Text segement : 存放使用者程式的 binary code 。
* 裡頭變數的排序不一定是遞增或遞減。

---
### [Object File](https://www.slideshare.net/jserv/helloworld-internals)
* File Format :
* 每個 OS 所使用的 object 檔格式不盡相同, Linux 使用的是 **ELF** (Executable and Linkable Format),Windows 使用的是 **PE** (Portable Executable)。
* 可用於紀錄 **executable file、object file、share object、core dump**。
* **.o** 檔 (object file) 是介於 compiling 和 linking 的檔案,經過編譯但還未連結為可執行檔。
* object file 中的 section 排列順序與 process 的 virtual memory address (VMA) 順序顛倒。
* MMU(memory management unit) : 負責處理 CPU 對記憶體的存取請求,例如虛擬位址到實體位址的轉換。
* user space process 會透過 MMU 從 virtual memory 映射至 physical memory,kernel space process 則是一直存在於 physical memory。
* File Content : (可以使用 `readelf` 去查看二進位檔的結構。)

1. .text section : 程式碼的部分。
2. .data section : 宣告並且有賦值的變數。
3. .bss section : 只有宣告,尚未初始化的變數。
* Compilation and Linking:
* 原始 .c 檔與 .h 檔經過編譯成為 .object 檔,最後再與其他 .object 檔或是 static lib 進行 linking 產生 .out 。
* Symbol:
* 可使用 `nm` 去查看二進位檔的 `SYMBOL` 位置。
* Symbol name 包含 function name 、 variable name。
* 每個 .object 檔都有個 symbol table ,存放 symbol value 。
---
### Static linking
* Methods :
1. Accumulate : 所有 section 依序排放在一起。
2. Merge similar section : 根據 .text 、 .data 、 .bss section 同類的放在一起。
* **.a** 檔 : object 檔的彙集,可以透過 linker 來與其他 object 檔做連結,ex. libc.a 。
### Dynamic linking
* **.so** 檔 : 為 Dynamic Shared Objects , dynamic loader 會在程式的執行期間讀入 .so 檔至記憶體,並做 relocation 。
* 較省空間,(.so file in linux),當需要使用到其他的 lib 時才會 load 進 memory 。
* Program1 與 Program2 在執行期間才動態連結 dynamic shared lib 。

---
### Parameter vs Argument
* 兩者為形式上的不同,但都可稱為參數
* formal parameter 為型別與符號 ex. int x 。
* actual argument 為數值 ex. 5 。
---
reference: C 程式語言 page 4-5
---
### [Stack](http://gghh.name/dibtp/2015/11/11/function-calls-in-c-practical-example.html)
* 包含了 parameter 、 local variable 、 return address 等。
* rbp 與 rsp 都是 x86 架構的暫存器。
* **rbp (frame pointer)** : 指向目前 stack frame 的起始位址。
* **rsp (stack pointer)** : 指向目前 stack frame 的末端位址,會隨著 stack 增長而增加。
* **return address** : 當目前的 stack frame 結束後要回去的位址。

1. Call function,**push** return address 到 Stack (給 instruction pointer使用) 。
2. [Function prologue](https://manybutfinite.com/post/journey-to-the-stack/) :
a. 先 `PUSH` 目前 `rbp` 的位址。
b. 將 `rsp` 複製至 `rbp` 。(兩者指向目前 stack frame 的起點)
c. `rsp` 開始往下移動(由高位址往低位址),保留空間給 local variables 。
3. [Function epilogue](https://manybutfinite.com/post/epilogues-canaries-buffer-overflows/) :
a. 將目前 `rbp` 複製至 `rsp` ,之前的 local variables 也被釋放了。(兩者指向目前 stack frame 的起點)
b. **Pop** 上個 `rbp` 的位址,讓目前的 `rbp` 回復成上個 stack frame 的 `rbp` 。
c. **Pop** return address 讓 instruction pointer 指向 call function 後的下道指令。
---
### Heap
* `free()` 為釋放 pointer 所指向之記憶體空間,非 pointer 本身。
* `free()` 後 pointer 不會在指向任何記憶體,如果再次 `free()` 就會產生 error。
* 釋放後可將 pointer 指向 NULL,防止二次釋放。
:::warning
:question:
[ ==Homework== ] 為什麼 glibc 可以偵測出上述程式的 "double free or corruption" 呢?如何去管理
:::
:::success
* source : [ glibc/malloc/malloc.c] #line 344 (https://github.com/lattera/glibc/blob/master/malloc/malloc.c) 可以下關鍵字 `_int_free` 來看 glibc 是如何實作 `free()` 。
* 講解 glibc 如何偵測 double free 前,需要先解釋幾個名詞 :
* `struct malloc_chunk` : 一個 doubly linked list 的資料結構的節點,每個節點除了雙向指標外,還存有目前節點大小與前節點大小。
* `fastbins` : 是個存有最近釋放掉的 `malloc_chunk` 的 single linked list。
* `mchunkptr` : 是一個 pointer to `malloc_chunk`。
* 解釋 : 當一個 pointer 被 `free()` 時,會先透過 `mem2chunk` 來找到其對應的 `mchunkptr` , 接著會去 `fastbins` 裡比對 `mchunkptr` 所指向的位址是否已經存在,有則表示之前此位址已經被 `free()` 過了,故產生 "double free or corruption" 的 error message 。
:::
> 這裡有個有趣的點,你可以嘗試看看 free 兩個 fastbin 大小的 chunk,順序:A, B, A,看看會發生什麼事
> [name=HexRabbit][color=purple]
:::info
memory allocator 內部實作可參照春季班課程報告: [rpmalloc 探討](https://hackmd.io/s/H1TP6FV6z)
:notes: jserv
:::