您好,登錄后才能下訂單哦!
本篇內容主要講解“如何使用Rust進行Linux kernel開發”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“如何使用Rust進行Linux kernel開發”吧!
長期以來,Rust 編程語言的一個目標都是能替代在操作系統內核開發中最常用的 C 語言。隨著 Rust 的逐步成熟,許多開發人員越來越有興趣在 Linux 內核中嘗試 Rust。在 2020 (virtual) Linux Plumbers Conference 會議上,LLVM 這個微會議的諸多議題中就舉辦了一場討論,關于 Linux 內核中接受 Rust 代碼還有那些未解決的問題或者障礙。這是 2020 年活動中參加人數最多的一次會議,從中可以看出人們對這個議題有多么感興趣了。
這個會議之前已經有許多開發者做了不少工作了,包括去年 Alex Gaynor 和 Geoffrey Thomas在 Linux Security Summit 安全峰會上的一次演講。當時,他們介紹了 Rust 內核模塊的一個原型,并提出了在內核中采用 Rust 的理由。他們的重點是在安全問題上,指出在 Android 和 Ubuntu 中,約有三分之二的內核漏洞被分配到 CVE 中,這些漏洞都是來自于內存安全問題。原則上,Rust 可以通過其 type system 和 borrow checker 所提供的更安全的 API 來完全避免這類錯誤。
此后,Linus Torvalds 和其他核心內核維護者都表示原則上對支持 Rust 的內核開發持開放態度,因此 Plumbers 的會議旨在列出具體能讓 Rust 進入 Linux kernel 的一些要求。這次會議是在 linux-kernel 郵件列表上提出并討論的,當時就已經提出了一部分討論主題。
這次會議的主角也是 Thomas 和 Gaynor,還有 Josh Triplett——Rust 語言團隊的聯合領導者,也是一位長期從事 Linux 內核開發的人——以及其他一些對此感興趣的開發者。他們簡單地談了一下他們到目前為止的工作,以及他們最初的一些想法和問題,然后的大部分時間進行討論。他們舉了一個簡單的例子,說明內核模式的 Rust 代碼可能是什么樣的(來自 Thomas 和 Gaynor 的 linux-kernel-module-rust 項目,https://github.com/fishinabarrel/linux-kernel-module-rust/)。
發言者強調,他們并不是提議將 Linux 內核重寫成 Rust,他們只是關注于走向一個可以用 Rust 編寫新代碼的世界。接下來的對話集中在 Rust 支持的三個潛在關注點上:利用內核中現有的 API,架構支持,以及關于 Rust 和 C 之間 ABI 兼容性的問題。
要想對內核開發能有實際價值的話,Rust 如果只是能夠生成可以鏈接到內核的代碼,這是不夠的,還需要有一種方法讓 Rust 能夠訪問 Linux 內核中在使用的大量 API,目前這些 API 都是在 C 頭文件中定義的。Rust 對與 C 代碼的互操作有很好的支持,包括既支持使用 C ABI 調用函數,也支持定義與 C 兼容的 ABI 的函數,這些函數可以由 C 語言中調用。此外,bindgen 工具能夠解析 C 頭文件,生成相應的 Rust 聲明,這樣 Rust 就不需要從 C 中重復定義,這也提供了一定程度的跨語言類型檢查。
從表面上看,這些特性使 Rust 具備了與現有 C API 集成的能力,但魔鬼就在細節中,迄今為止的工作和會議上的對話都說明這里實現中有不少的挑戰。例如,Linux 大量使用預處理宏(preprocessor macro)和內聯函數(inline function),而這些函數并不容易被 bindgen 和 Rust 的 foreign-function interface 接口所支持。
例如,非常常用的 kmalloc() 函數就被定義為 __always_inline,這意味著它的所有調用都是 inline 的,內核符號表中沒有 kmalloc() 符號, Rust 也就無法進行鏈接調用。這個問題可以很容易地解決,我們可以定義一個包含非 inline 版本的 kmalloc_for_rust() 符號,但是手工處理這些變通解決方案會導致大量的手工工作和重復的代碼。這項工作有可能通過改進版的 bindgen 自動完成,但目前工具還不具備這個功能。
對話中還提到了第二個關于 API 綁定的問題:C API 需要進行多大程度的手動 "wrapped(包裝)"才能提供出地道的 Rust 接口?看看現有的兩個 Rust 內核模塊項目,就能體會到這里的一些麻煩。
在 linux-kernel-module-rust 項目中,進入用戶空間的指針被 wrap 成 UserSlicePtr 類型,這確保了 copy_to_user()或 copy_from_user()的可以正確使用。這個 wrapper 在 Rust 代碼中提供了一定程度的安全性功能(因為這類指針不能直接 dereference),同時也使 Rust 代碼更加地道。要想寫入用戶空間指針的話,代碼看起來就像是這樣:
user_buf.write(&kernel_buffer)?
這里的"?"是 Rust 錯誤處理機制的一部分,這種 return and handling error 的處理風格在 Rust 中無處不在。這類 wrapper 使現有的 Rust 開發者更加熟悉所產生的 Rust,并使 Rust 的 type system 和 borrow checker 能夠盡量確保安全。然而,每一個 API 都需要這樣的精心設計和開發,工作量巨大,也會導致 C 和 Rust 編寫的模塊有不同的 API。
John Baublitz 的 demo module(https://github.com/jbaublitz/knock-out ),則是直接地綁定了內核的用戶訪問函數。相應的代碼看起來是這樣的:
if kernel::copy_to_user(buf, &kernel_buffer[0...count]) != 0 {
return -kernel::EFAULT;
}
這種改法實現起來很容易,binding 主要是由 bindgen 自動生成的,而且對于現有的內核開發者來說,他們也會不那么排斥 review 或者修改 Rust 代碼。然而,對于 Rust 開發者來說,這種代碼就不那么習慣了,而且可能會損失 Rust 原本可以保證的一些安全性。
會議上大家一致認為,對于一些最常見的關鍵 API,有必要編寫 Rust 版本的 wrapper,但不可能對每一個內核 API 都手動去寫一個 wrapper,這是不可取的做法。Thomas 提到 Google 正在研究自動生成 C++代碼的規范化綁定動作,不知道內核是否可以做一些類似的事情,也許是建立在現有的 sparse annotation(kernel 中使用的語義檢查工具)基礎之上,或者是在現有的 C 代碼中添加一些新的注釋來引導 binding generator 的工作。
下一個討論話題是架構支持。目前,唯一成熟 Rust 編譯器只有 rustc 這一個,它是通過 LLVM 來生成指令碼。Linux 內核支持許多種體系架構,其中一些架構并沒有現成的 LLVM 后端(backend)。其他一些架構存在 LLVM 后端,但 rustc 還尚未不支持該后端。演講者想知道,全架構支持是否是在內核中啟用 Rust 的一個障礙。
有幾個人說,在 Rust 中實現驅動是可以接受的,但無論如何,這些驅動永遠不會用在比較少見的架構上。Triplett 以他在 Debian 項目中的經驗為例,認為在內核中加入 Rust 將有助于推動更多架構對 Rust 的支持。他提到,將 Rust 軟件引入 Debian 有助于激勵小眾架構的愛好者和用戶提高對 Rust 的支持,他認為在內核中加入 Rust 后也會有類似的效果。尤其是,任何具有 LLVM 后端的架構預計都可以很快得到 rustc 的支持。
對話中也提及了還有其他一些可選的 Rust 實現版本,這樣可以有助于支持更多的架構。mrustc 項目就是一個實驗性的 Rust 編譯器,它可以生成 C 代碼。使用 mrustc 有可能可以讓 Rust 通過編譯內核其他部分所用的那個 C 編譯器來編譯。
此外,Triplett 還提到了一些針對 GCC 的 Rust 前端(front end)的工作,這些工作有可能使 Rust 能夠支持 GCC 所支持的任一架構。這個項目還處于早期階段,但它也提供了另一條途徑,可以在將來彌補架構支持方面的缺陷。本節的結論雖然沒有給出非常確定的答案,但看起來似乎并沒有人強烈反對這個“先支持 Rust 設備驅動程序再完成更多架構支持”的計劃。
Gaynor 還就 ABI 的兼容性問題請教大家。由于 Rust(目前)是通過 LLVM 編譯的,而內核主流上來說還是用 GCC 構建的,因此,將 Rust 代碼鏈接到內核中可能意味著混合 GCC 和 LLVM 生成的代碼。盡管 LLVM 的目標是與 GCC 的 ABI 兼容,但還是有點擔心這種做法會造成微小的 ABI 不兼容的風險,因此碰到一些阻力。演講者們想知道內核社區是否更愿意將 Rust 的支持限制在用 Clang 構建的內核上,從而確保兼容性。
Greg Kroah-Hartman 確認說當前的內核規則是:只有當內核中的所有對象文件(object file)都是用相同的編譯器,使用相同的 flags 來構建時,兼容性才會得到保證。然而,他也表示,可以將 LLVM 構建的 Rust object 鏈接到 GCC 構建的內核中,只要這些對象是同時構建的,并設置了適當的選項,而且所產生的這組 configuration 是經過充分測試的,那就可以。他認為在沒有出現實際問題之前,沒有必要進行額外的限制。Florian Weimer 澄清說,ABI 問題往往是在語言中不明顯的角落。例如,通過返回值來返回一個包含 bitfield 的結構這種情況。他認為 ABI 中最主要且常用的部分應該不會造成兼容性問題。
Triplett 強調,GCC 和 Rust 之間的調用在用戶空間中是很常見的,也是正常用法,所以從 Rust 方面來說,他并不擔心兼容性問題。聽起來,這個問題最終應該不會成為將 Rust 引入內核的障礙。
會議結束時沒有定出具體的下一步,但總體看來,人們對最終支持 Rust module 的熱情以及需求 越來越形成了一致意見。下一個重要的步驟很可能是某人提出一個真正的 Rust 驅動,并將其納入內核。只要有一個具體的用例和實現,總是大力推動來搞清楚任何剩余有爭議的問題,并達成設計結論。
到此,相信大家對“如何使用Rust進行Linux kernel開發”有了更深的了解,不妨來實際操作一番吧!這里是億速云網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續學習!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。