glibc 原始碼內部與系統呼叫包裝器

最後更新: 2026-05-07 03:47:31 +0800 +0800
原文以英文撰寫。您正在閱讀AI翻譯版本。

glibc 暴露 read(2) 與 write(2) 等 C 函式,而 Linux 暴露架構特定的系統呼叫進入慣例。包裝器連接這些層:它接受公開 C ABI,遵循選定架構的系統呼叫 ABI,轉譯核心錯誤,並可能實作 POSIX 執行緒取消行為。

以下範例描述目前的上游原始碼樹。已發布的 glibc 可能選取不同檔案或巨集定義,因此檢查原始碼必須從正在建置的發布版本與目標三元組開始。

sysdeps/ 選取 #

sysdeps/ 樹 保存依作業系統、CPU、ABI、字組大小與功能選取的實作。通用程式碼是後備方案;更具體的目錄可以使用相同相對名稱取代檔案。對 Linux 建置而言,相關路徑包括 sysdeps/unix/sysv/linux/;架構還可以提供 Linux 特定進入程式碼或 ABI 特定變體。

glibc 的設定與建置機制會建立適用系統相依目錄的有序清單。建置規則搜尋該清單,使選取的實作優先於通用後備方案。因此,這種配置不是每個檔案都恰好具有一個維度的分類法:作業系統目錄可能依賴架構標頭,而架構目錄可能包含與作業系統無關的程式碼。不要從單一目錄名稱推論行為,應檢查 config.make、已設定的建置目錄與選取的原始碼路徑。

產生的精簡包裝器 #

部分精簡組合語言包裝器會從 syscalls.list 產生。每筆記錄會命名輸出、Linux 系統呼叫、引數簽章、強符號,以及選用的弱符號或版本化名稱。建置會呼叫 make-syscalls.sh,它會:

  1. 移除被較高優先級 sysdeps 目錄覆寫的項目;
  2. 透過目標的 sysdep.h 解析 SYS_ 編號;
  3. 從簽章推導參數數量與特殊引數處理;以及
  4. 使用 syscall-template.S 產生規則,並在清單要求時包含別名與相容性符號。

syscalls.list 不會定義每個公開函式。具有驗證、後備邏輯、取消處理、時間寬度轉換或其他政策的包裝器通常是手寫的。目前 glibc 的 write.c 中的 write 就是這類手寫 C 包裝器;因此它可與產生路徑形成有用對照。

write 與可感知取消的分派 #

概念上,Linux write 包裝器會執行以下操作:

c
ssize_t
write(int fd, const void *buffer, size_t count)
{
    return cancellation_aware_syscall(SYS_write, fd, buffer, count);
}

實際原始碼會呼叫 SYSCALL_CANCEL (write, fd, buf, nbytes)。當不需要檢查取消時,該巨集會選取內嵌系統呼叫路徑;否則會暫時變更執行緒的取消型別,發出呼叫,然後還原先前的型別。write 是 POSIX 取消點,因此此邊界讓待處理的取消得以執行,而不會將每個內部系統呼叫都視為取消點。

巨集會依引數數量進行分派,之後才到達架構的內嵌系統呼叫原語。在 Linux 上,該原語會將系統呼叫編號與引數放入目標 ABI 規定的暫存器,執行架構的系統呼叫指令,並接收核心回傳值。C 函式 ABI 或暫存器順序都不是通用的:x86-64、i386、AArch64 與其他連接埠使用不同暫存器與破壞規則。

核心會依其低階慣例回傳錯誤。選取的 glibc 支援程式碼會辨識錯誤範圍,將正值錯誤編號儲存到執行緒本地的 errno,並使一般公開包裝器回傳 -1。刻意暴露原始錯誤值的介面會使用不同的內部慣例。glibc 手冊的系統呼叫章節記錄應用程式層級契約;原始碼巨集則實作架構特定的邊界。

公開名稱、隱藏定義與別名 #

write.c 定義名為 __libc_write,接著其原始碼宣告內部可見性與包括 __write 及公開 write 名稱在內的別名。這種形式將實作身分與公開 ABI 身分分開:

  • libc_hidden_def 與 libc_hidden_weak 讓 libc 內部的呼叫在適當時繫結到隱藏定義,避免可插入的公開符號查找。
  • 強別名會讓另一個內部名稱使用相同實作。
  • 弱公開別名允許其他定義在建置或 ABI 要求時覆寫它。
  • 符號版本機制會記錄公開名稱匯出的 ABI 版本,並可為舊二進位檔保留相容進入點。

hidden 會影響 glibc 內的參照;它不會從共用函式庫 ABI 中刪除文件化的公開符號。診斷未解析符號時,使用 readelf --dyn-syms --version-info 檢查架構的 libc.so,並與原始碼及發布版本指令碼比較。單獨的別名宣告不足以證明分發函式庫匯出的版本。

評論

在 GitHub 上閱讀或評論(發表評論需要登入)