在 glibc 和一般的 Linux 程式執行流程中,以下是這幾個函式的包含關係和呼叫順序:
1. `_start`:
- 是程式執行的入口點,通常由編譯器自動提供。
- 它負責初始化程式,收集命令列引數以及環境變數,並準備呼叫 `__libc_start_main`。
2. `__libc_start_main`:
- 這是 glibc 提供的啟動例程,由 `_start` 呼叫。
- 它負責更多的初始化工作,比如 I/O 設定、國際化支援、各種 lock 的初始化等。
- 它也會設定程式退出時呼叫的 `exit` 函式。
- 在這之後,`__libc_start_main` 會呼叫使用者定義的 `main` 函式。
3. `main`:
- 使用者編寫的程式主體函式。
- 執行完使用者程式碼後,它會返回一個值通常表示程式退出狀態。
4. `exit`:
- 使用者的 `main` 函式返回後,`__libc_start_main` 會呼叫 `exit` 函式。
- 它負責呼叫透過 `atexit` 或 `on_exit` 註冊的清理函式。
- 它會關閉所有的標準 C 庫 I/O 流並清理臨時檔案等。
5. `init` 和 `fini`(也稱為`__attribute__((constructor))` 和 `__attribute__((destructor))` 函式):
- `init`: 這些是使用者定義的,或者在某些情況下是由特定庫提供的初始化函式,它們在 `main` 函式執行之前呼叫。
- `fini`: 這些函式在 `exit` 呼叫之前執行,是對應的終止函式,用於執行任何必要的清理工作。
6. `rtld_fini`:
- 這是動態連結器的清理函式,由 `__libc_start_main` 在 `exit` 之前呼叫。
- 它是用於動態連結器清理其資源。
結合起來的呼叫關係和順序如下:
_start() -> 初始化 -> 呼叫 __libc_start_main | |-> __libc_start_main(main, argc, argv, init, fini, rtld_fini, stack_end) |-> 呼叫 init 函式 (如果有的話) |-> 呼叫 main 函式 |-> main 函式返回 |-> 呼叫 fini 函式 (如果有的話) |-> 呼叫 exit 函式 |-> 呼叫透過 atexit/on_exit 註冊的所有終止處理函式 |-> 呼叫 rtld_fini 清理動態連結器資源 (如果有的話) |-> 清理 C 庫資源,關閉檔案等 |-> 程序終止,返回退出狀態給作業系統
以上是個高階概述;實際實現細節可能因具體的 Linux 釋出版本和 glibc 版本而異。