# DTrace Tail-Call Optimization 問題


## 正文

我在 DTrace 的時候，有時候會看到以下奇怪的 log，有奇怪的回傳值：

```sh
  0  52547 casper_mpo_socket_check_poll_t:return casper_mpo_socket_check_poll_t returned 0
  0  52549 casper_mpo_socket_check_receive_t:return casper_mpo_socket_check_receive_t returned 0
  0  52625 casper_mpo_vnode_check_lookup:return casper_mpo_vnode_check_lookup returned 0
  0  52625 casper_mpo_vnode_check_lookup:return casper_mpo_vnode_check_lookup returned 0
  0  52631 casper_mpo_vnode_check_open:return casper_mpo_vnode_check_open returned -105548670090024
  0  52681 casper_check_allowed_open:return casper_check_allowed_open returned 0
  0  52659 casper_mpo_vnode_check_stat_t:return casper_mpo_vnode_check_stat_t returned 0
  0  52635 casper_mpo_vnode_check_read_t:return casper_mpo_vnode_check_read_t returned 0
```

這是因為我的程式碼是這樣寫：

```c
int casper_mpo_vnode_check_open(...) {
    // ... 一些檢查 ...
    return casper_check_allowed_open(...); 
}
```

編譯器（如 Clang/LLVM）發現 casper_mpo_vnode_check_open 在呼叫完 casper_check_allowed_open 後就沒事做了。為了優化效能：

1. 它不會使用 call 指令（這會產生新的 Stack Frame）
2. 它會直接使用 jmp 指令跳到下一個函數
3. 它會直接重複使用目前的 Stack Frame

DTrace 的 fbt (Function Boundary Tracing) 依賴於函數的進入與退出指令（入口的 push %rbp 和出口的 ret）：

1. 因為使用了 jmp 而不是 ret，casper_mpo_vnode_check_open 的 fbt:::return 探針可能根本不會在正確的時間點觸發，或者是在執行 jmp 之前就觸發了
2. 當 DTrace 試圖抓取 %rax 時，被呼叫的子函數（casper_check_allowed_open）可能還沒把真正的結果（例如 0）放進去。此時 %rax 裡裝的是上一個指令殘留的記憶體位址或指標，轉換成十進位就變成了你看到的奇怪負數

