glibc中_start、__libc_start_main、main、exit、init、finit、rtld_fini這幾個函式的包含關係和呼叫先後順序是什麼

墨尔基阿德斯發表於2024-11-05

在 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 版本而異。

相關文章