成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

如何用 Rust 編寫一個 Linux 內核模塊

開發 后端 Linux
近些年來 Rust 語言由于其內存安全性和性能等優勢得到了很多關注,尤其是 Linux 內核也在準備將其集成到其中,因此,我們特邀阿里云工程師蘇子彬為我們介紹一下如何在 Linux 內核中集成 Rust 支持。

編者按:近些年來 Rust 語言由于其內存安全性和性能等優勢得到了很多關注,尤其是 Linux 內核也在準備將其集成到其中,因此,我們特邀阿里云工程師蘇子彬為我們介紹一下如何在 Linux 內核中集成 Rust 支持。 

2021 年 4 月 14 號,一封主題名為《Rust support》的郵件出現在 LKML 郵件組中。這封郵件主要介紹了向內核引入 Rust 語言支持的一些看法以及所做的工作。郵件的發送者是 Miguel Ojeda,為內核中 Compiler attributes、.clang-format 等多個模塊的維護者,也是目前 Rust for Linux 項目的維護者。

Rust for Linux 項目目前得到了 Google 的大力支持Miguel Ojeda 當前的全職工作就是負責 Rust for Linux 項目。

長期以來,內核使用 C 語言和匯編語言作為主要的開發語言,部分輔助語言包括 Python、Perl、shell 被用來進行代碼生成、打補丁、檢查等工作。2016 年 Linux 25 歲生日時,在對 Linus Torvalds 的一篇 采訪中,他就曾表示過:

這根本不是一個新現象。我們有過使用 Modula-2 或 Ada 的系統人員,我不得不說 Rust 看起來比這兩個災難要好得多。

我對 Rust 用于操作系統內核并不信服(雖然系統編程不僅限于內核),但同時,毫無疑問,C 有很多局限性。

在最新的對 Rust support 的 RFC 郵件的回復中,他更是說:

所以我對幾個個別補丁做了回應,但總體上我不討厭它。

沒有用他特有的回復方式來反擊,應該就是暗自喜歡了吧。

目前 Rust for Linux 依然是一個獨立于上游的項目,并且主要工作還集中的驅動接口相關的開發上,并非一個完善的項目。

項目地址: https://github.com/Rust-for-Linux/linux

為什么是 Rust

在 Miguel Ojeda 的第一個 RFC 郵件中,他已經提到了 “Why Rust”,簡單總結下:

  • 安全子集safe subset中不存在未定義行為,包括內存安全和數據競爭;
  • 更加嚴格的類型檢測系統能夠進一步減少邏輯錯誤;
  • 明確區分 safe 和 unsafe 代碼;
  • 更加面向未來的語言:sum 類型、模式匹配、泛型、RAII、生命周期、共享及專屬引用、模塊與可見性等等;
  • 可擴展的獨立標準庫;
  • 集成的開箱可用工具:文檔生成、代碼格式化、linter 等,這些都基于編譯器本身。

編譯支持 Rust 的內核

根據 Rust for Linux 文檔,編譯一個包含 Rust 支持的內核需要如下步驟:

  1. 安裝 rustc 編譯器。Rust for Linux 不依賴 cargo,但需要最新的 beta 版本的 rustc。使用 rustup命令安裝:

    1. rustup default beta-2021-06-23
  2. 安裝 Rust 標準庫的源碼。Rust for Linux 會交叉編譯 Rust 的 core 庫,并將這兩個庫鏈接進內核鏡像。

    1. rustup component add rust-src
  3. 安裝 libclang 庫。libclang 被 bindgen 用做前端,用來處理 C 代碼。libclang 可以從 llvm 官方主頁 下載預編譯好的版本。

  4. 安裝 bindgen 工具,bindgen 是一個自動將 C 接口轉為 RustFFI 接口的庫:

    1. cargo install --locked --version 0.56.0 bindgen
  5. 克隆最新的 Rust for Linux 代碼:

    1. git clone https://github.com/Rust-for-Linux/linux.git
  6. 配置內核啟用 Rust 支持:

    1. Kernel hacking
    2. -> Sample kernel code
    3. -> Rust samples
  7. 構建:

    1. LIBCLANG_PATH=/path/to/libclang make -j LLVM=1 bzImage

    這里我們使用 clang 作為默認的內核編譯器,使用 gcc 理論上是可以的,但還處于 早期實驗 階段。

Rust 是如何集成進內核的

目錄結構

為了將 Rust 集成進內核中,開發者首先對 Kbuild 系統進行修改,加入了相關配置項來開啟/關閉 Rust 的支持。

此外,為了編譯 rs 文件,添加了一些 Makefile 的規則。這些修改分散在內核目錄中的不同文件里。

Rust 生成的目標代碼中的符號會因為 Mangling 導致其長度超過同樣的 C 程序所生成符號的長度,因此,需要對內核的符號長度相關的邏輯進行補丁。開發者引入了 “大內核符號”的概念,用來在保證向前兼容的情況下,支持 Rust 生成的目標文件符號長度。

其他 Rust 相關的代碼都被放置在了 rust 目錄下。

在 Rust 中使用 C 函數

Rust 提供 FFI(外部函數接口Foreign Function Interface)用來支持對 C 代碼的調用。Bindgen 是一個 Rust 官方的工具,用來自動化地從 C 函數中生成 Rust 的 FFI 綁定。內核中的 Rust 也使用該工具從原生的內核 C 接口中生成 Rust 的 FFI 綁定。

  1. quiet_cmd_bindgen = BINDGEN $@
  2. cmd_bindgen = \
  3. $(BINDGEN) $< $(shell grep -v '^\#\|^$$' $(srctree)/rust/bindgen_parameters) \
  4. --use-core --with-derive-default --ctypes-prefix c_types \
  5. --no-debug '.*' \
  6. --size_t-is-usize -o $@ -- $(bindgen_c_flags_final) -DMODULE
  7.  
  8. $(objtree)/rust/bindings_generated.rs: $(srctree)/rust/kernel/bindings_helper.h \
  9. $(srctree)/rust/bindgen_parameters FORCE
  10. $(call if_changed_dep,bindgen)

ABI

Rust 相關的代碼會單獨從 rs 編譯為 .o,生成的目標文件是標準的 ELF 文件。在鏈接階段,內核的鏈接器將 Rust 生成的目標文件與其他 C 程序生成的目標文件一起鏈接為內核鏡像文件。因此,只要 Rust 生成的目標文件 ABI 與 C 程序的一致,就可以無差別的被鏈接(當然,被引用的符號還是要存在的)。

Rust 的 alloc 與 core 庫

目前 Rust for Linux 依賴于 core 庫。在 core 中定義了基本的 Rust 數據結構與語言特性,例如熟悉的 Option<> 和 Result<> 就是 core 庫所提供。

這個庫被交叉編譯后被直接鏈接進內核鏡像文件,這也是導致啟用 Rust 的內核鏡像文件尺寸較大的原因。在未來的工作中,這兩個庫會被進一步被優化,去除掉某些無用的部分,例如浮點操作,Unicode 相關的內容,Futures 相關的功能等。

之前的 Rust for Linux 項目還依賴于 Rust 的 alloc 庫。Rust for Linux 定義了自己的 GlobalAlloc 用來管理基本的堆內存分配。主要被用來進行堆內存分配,并且使用 GFP_KERNEL 標識作為默認的內存分配模式。

不過在在最新的 拉取請求 中,社區已經將移植并修改了 Rust的 alloc 庫,使其能夠在盡量保證與 Rust 上游統一的情況下,允許開發者定制自己的內存分配器。不過目前使用自定義的 GFP_ 標識來分配內存依然是不支持的,但好消息是這個功能正在開發中。

“Hello World” 內核模塊

用一個簡單的 Hello World 來展示如何使用 Rust 語言編寫驅動代碼,hello_world.rs:

  1. #![no_std]
  2. #![feature(allocator_api, global_asm)]
  3.  
  4. use kernel::prelude::*;
  5.  
  6. module! {
  7. type: HelloWorld,
  8. name: b"hello_world",
  9. author: b"d0u9",
  10. description: b"A simple hello world example",
  11. license: b"GPL v2",
  12. }
  13.  
  14. struct HelloWorld;
  15.  
  16. impl KernelModule for HelloWorld {
  17. fn init() -> Result<Self> {
  18. pr_info!("Hello world from rust!\n");
  19.  
  20. Ok(HelloWorld)
  21. }
  22. }
  23.  
  24. impl Drop for HelloWorld {
  25. fn drop(&mut self) {
  26. pr_info!("Bye world from rust!\n");
  27. }
  28. }

與之對應的 Makefile

  1. obj-m := hello_world.o

構建:

  1. make -C /path/to/linux_src M=$(pwd) LLVM=1 modules

之后就和使用普通的內核模塊一樣,使用 insmod 工具或者 modprobe 工具加載就可以了。在使用體驗上是沒有區別的。

module! { } 宏

這個宏可以被認為是 Rust 內核模塊的入口,因為在其中定義了一個內核模塊所需的所有信息,包括:AuthorLicenseDescription 等。其中最重要的是 type 字段,在其中需要指定內核模塊結構的名字。在這個例子中:

  1. module! {
  2. ...
  3. type: HelloWorld,
  4. ...
  5. }
  6.  
  7. struct HelloWorld;

module_init() 與 module_exit()

在使用 C 編寫的內核模塊中,這兩個宏定義了模塊的入口函數與退出函數。在 Rust 編寫的內核模塊中,對應的功能由 trait KernelModule 和 trait Drop 來實現。trait KernelModule 中定義 init() 函數,會在模塊驅動初始化時被調用;trait Drop 是 Rust 的內置 trait,其中定義的 drop() 函數會在變量生命周期結束時被調用。

編譯與鏈接

所有的內核模塊文件會首先被編譯成 .o 目標文件,之后由內核鏈接器將這些 .o 文件和自動生成的模塊目標文件 .mod.o 一起鏈接成為 .ko 文件。這個 .ko 文件符合動態庫 ELF 文件格式,能夠被內核識別并加載。

其他

完整的介紹 Rust 是如何被集成進內核的文章可以在 我的 Github 上找到,由于寫的倉促,可能存在一些不足,還請見諒。

作者簡介

蘇子彬,阿里云 PAI 平臺開發工程師,主要從事 Linux 系統及驅動的相關開發,曾為 PAI 平臺編寫 FPGA 加速卡驅動。 

 

責任編輯:龐桂玉 來源: Linux中國
相關推薦

2014-07-24 14:35:26

Linux內核模塊

2018-06-19 09:07:57

Linux內核模塊

2010-01-22 11:01:04

linux內核模塊

2011-08-29 15:12:24

UbuntuLinux模塊

2019-07-08 20:00:35

Linux內核模塊

2023-05-08 08:05:42

內核模塊Linux

2010-04-12 11:19:47

編譯內核模塊

2021-09-03 08:44:51

內核模塊Linux社區

2022-05-14 17:01:21

開源LinuxNVIDIA

2009-12-17 15:28:32

內核模塊編譯

2021-03-11 12:19:39

Linux運維Linux系統

2022-05-12 09:58:31

LinuxNVIDIA開源

2018-05-14 09:48:45

Linux內核模塊Kgotobed

2021-01-03 16:30:34

Rust編程語言

2013-09-10 09:54:50

2009-09-11 08:44:36

2023-02-26 01:37:57

goORM代碼

2020-05-13 21:11:37

KVM架構工具

2018-10-15 10:10:41

Linux內核補丁

2024-04-16 08:09:36

JavapulsarAPI
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 伊人影院在线观看 | 亚洲精品一区二区三区免 | 亚洲天堂中文字幕 | 成人不卡视频 | 亚洲一区二区日韩 | 国产一区二区精品在线观看 | 天天综合永久 | 91精品国产综合久久久久 | 国产精品久久久久一区二区 | 精品欧美激情精品一区 | 欧美日韩在线综合 | 久久久久久久久久久一区二区 | 一区二区三区在线播放 | 国产在线播 | 久久久久久久久久久一区二区 | 91精品国产91| 成人性生交a做片 | 午夜在线免费观看 | 欧美一区二区三区电影 | 国产精品视频网站 | 黄色大片免费网站 | 日本不卡一区二区三区在线观看 | 狠狠干狠狠操 | 亚洲精品一区二区三区四区高清 | 毛片免费在线 | 成人99| 成人欧美日韩一区二区三区 | 久久免费精品 | 日韩精品视频在线 | 亚洲一本 | 欧美一区二区在线免费观看 | 天天操 天天操 | 亚洲精品一区久久久久久 | 二区三区av | www.国产一区 | 四虎永久免费地址 | www.嫩草 | 亚洲网站在线 | 日韩欧美一区二区三区免费看 | 国产成人精品一区二区三区四区 | 91精品国产综合久久久亚洲 |