偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

如何用 Rust 編寫(xiě)一個(gè) Linux 內(nèi)核模塊

開(kāi)發(fā) 后端 Linux
近些年來(lái) Rust 語(yǔ)言由于其內(nèi)存安全性和性能等優(yōu)勢(shì)得到了很多關(guān)注,尤其是 Linux 內(nèi)核也在準(zhǔn)備將其集成到其中,因此,我們特邀阿里云工程師蘇子彬?yàn)槲覀兘榻B一下如何在 Linux 內(nèi)核中集成 Rust 支持。

編者按:近些年來(lái) Rust 語(yǔ)言由于其內(nèi)存安全性和性能等優(yōu)勢(shì)得到了很多關(guān)注,尤其是 Linux 內(nèi)核也在準(zhǔn)備將其集成到其中,因此,我們特邀阿里云工程師蘇子彬?yàn)槲覀兘榻B一下如何在 Linux 內(nèi)核中集成 Rust 支持。 

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

Rust for Linux 項(xiàng)目目前得到了 Google 的大力支持,Miguel Ojeda 當(dāng)前的全職工作就是負(fù)責(zé) Rust for Linux 項(xiàng)目。

長(zhǎng)期以來(lái),內(nèi)核使用 C 語(yǔ)言和匯編語(yǔ)言作為主要的開(kāi)發(fā)語(yǔ)言,部分輔助語(yǔ)言包括 Python、Perl、shell 被用來(lái)進(jìn)行代碼生成、打補(bǔ)丁、檢查等工作。2016 年 Linux 25 歲生日時(shí),在對(duì) Linus Torvalds 的一篇 采訪(fǎng)中,他就曾表示過(guò):

這根本不是一個(gè)新現(xiàn)象。我們有過(guò)使用 Modula-2 或 Ada 的系統(tǒng)人員,我不得不說(shuō) Rust 看起來(lái)比這兩個(gè)災(zāi)難要好得多。

我對(duì) Rust 用于操作系統(tǒng)內(nèi)核并不信服(雖然系統(tǒng)編程不僅限于內(nèi)核),但同時(shí),毫無(wú)疑問(wèn),C 有很多局限性。

在最新的對(duì) Rust support 的 RFC 郵件的回復(fù)中,他更是說(shuō):

所以我對(duì)幾個(gè)個(gè)別補(bǔ)丁做了回應(yīng),但總體上我不討厭它。

沒(méi)有用他特有的回復(fù)方式來(lái)反擊,應(yīng)該就是暗自喜歡了吧。

目前 Rust for Linux 依然是一個(gè)獨(dú)立于上游的項(xiàng)目,并且主要工作還集中的驅(qū)動(dòng)接口相關(guān)的開(kāi)發(fā)上,并非一個(gè)完善的項(xiàng)目。

項(xiàng)目地址: https://github.com/Rust-for-Linux/linux

為什么是 Rust

在 Miguel Ojeda 的第一個(gè) RFC 郵件中,他已經(jīng)提到了 “Why Rust”,簡(jiǎn)單總結(jié)下:

  • 安全子集safe subset中不存在未定義行為,包括內(nèi)存安全和數(shù)據(jù)競(jìng)爭(zhēng);
  • 更加嚴(yán)格的類(lèi)型檢測(cè)系統(tǒng)能夠進(jìn)一步減少邏輯錯(cuò)誤;
  • 明確區(qū)分 safe 和 unsafe 代碼;
  • 更加面向未來(lái)的語(yǔ)言:sum 類(lèi)型、模式匹配、泛型、RAII、生命周期、共享及專(zhuān)屬引用、模塊與可見(jiàn)性等等;
  • 可擴(kuò)展的獨(dú)立標(biāo)準(zhǔn)庫(kù);
  • 集成的開(kāi)箱可用工具:文檔生成、代碼格式化、linter 等,這些都基于編譯器本身。

編譯支持 Rust 的內(nèi)核

根據(jù) Rust for Linux 文檔,編譯一個(gè)包含 Rust 支持的內(nèi)核需要如下步驟:

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

    1. rustup default beta-2021-06-23
  2. 安裝 Rust 標(biāo)準(zhǔn)庫(kù)的源碼。Rust for Linux 會(huì)交叉編譯 Rust 的 core 庫(kù),并將這兩個(gè)庫(kù)鏈接進(jìn)內(nèi)核鏡像。

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

  4. 安裝 bindgen 工具,bindgen 是一個(gè)自動(dòng)將 C 接口轉(zhuǎn)為 RustFFI 接口的庫(kù):

    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. 配置內(nèi)核啟用 Rust 支持:

    1. Kernel hacking
    2. -> Sample kernel code
    3. -> Rust samples
  7. 構(gòu)建:

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

    這里我們使用 clang 作為默認(rèn)的內(nèi)核編譯器,使用 gcc 理論上是可以的,但還處于 早期實(shí)驗(yàn) 階段。

Rust 是如何集成進(jìn)內(nèi)核的

目錄結(jié)構(gòu)

為了將 Rust 集成進(jìn)內(nèi)核中,開(kāi)發(fā)者首先對(duì) Kbuild 系統(tǒng)進(jìn)行修改,加入了相關(guān)配置項(xiàng)來(lái)開(kāi)啟/關(guān)閉 Rust 的支持。

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

Rust 生成的目標(biāo)代碼中的符號(hào)會(huì)因?yàn)?nbsp;Mangling 導(dǎo)致其長(zhǎng)度超過(guò)同樣的 C 程序所生成符號(hào)的長(zhǎng)度,因此,需要對(duì)內(nèi)核的符號(hào)長(zhǎng)度相關(guān)的邏輯進(jìn)行補(bǔ)丁。開(kāi)發(fā)者引入了 “大內(nèi)核符號(hào)”的概念,用來(lái)在保證向前兼容的情況下,支持 Rust 生成的目標(biāo)文件符號(hào)長(zhǎng)度。

其他 Rust 相關(guān)的代碼都被放置在了 rust 目錄下。

在 Rust 中使用 C 函數(shù)

Rust 提供 FFI(外部函數(shù)接口Foreign Function Interface)用來(lái)支持對(duì) C 代碼的調(diào)用。Bindgen 是一個(gè) Rust 官方的工具,用來(lái)自動(dòng)化地從 C 函數(shù)中生成 Rust 的 FFI 綁定。內(nèi)核中的 Rust 也使用該工具從原生的內(nèi)核 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 相關(guān)的代碼會(huì)單獨(dú)從 rs 編譯為 .o,生成的目標(biāo)文件是標(biāo)準(zhǔn)的 ELF 文件。在鏈接階段,內(nèi)核的鏈接器將 Rust 生成的目標(biāo)文件與其他 C 程序生成的目標(biāo)文件一起鏈接為內(nèi)核鏡像文件。因此,只要 Rust 生成的目標(biāo)文件 ABI 與 C 程序的一致,就可以無(wú)差別的被鏈接(當(dāng)然,被引用的符號(hào)還是要存在的)。

Rust 的 alloc 與 core 庫(kù)

目前 Rust for Linux 依賴(lài)于 core 庫(kù)。在 core 中定義了基本的 Rust 數(shù)據(jù)結(jié)構(gòu)與語(yǔ)言特性,例如熟悉的 Option<> 和 Result<> 就是 core 庫(kù)所提供。

這個(gè)庫(kù)被交叉編譯后被直接鏈接進(jìn)內(nèi)核鏡像文件,這也是導(dǎo)致啟用 Rust 的內(nèi)核鏡像文件尺寸較大的原因。在未來(lái)的工作中,這兩個(gè)庫(kù)會(huì)被進(jìn)一步被優(yōu)化,去除掉某些無(wú)用的部分,例如浮點(diǎn)操作,Unicode 相關(guān)的內(nèi)容,F(xiàn)utures 相關(guān)的功能等。

之前的 Rust for Linux 項(xiàng)目還依賴(lài)于 Rust 的 alloc 庫(kù)。Rust for Linux 定義了自己的 GlobalAlloc 用來(lái)管理基本的堆內(nèi)存分配。主要被用來(lái)進(jìn)行堆內(nèi)存分配,并且使用 GFP_KERNEL 標(biāo)識(shí)作為默認(rèn)的內(nèi)存分配模式。

不過(guò)在在最新的 拉取請(qǐng)求 中,社區(qū)已經(jīng)將移植并修改了 Rust的 alloc 庫(kù),使其能夠在盡量保證與 Rust 上游統(tǒng)一的情況下,允許開(kāi)發(fā)者定制自己的內(nèi)存分配器。不過(guò)目前使用自定義的 GFP_ 標(biāo)識(shí)來(lái)分配內(nèi)存依然是不支持的,但好消息是這個(gè)功能正在開(kāi)發(fā)中。

“Hello World” 內(nèi)核模塊

用一個(gè)簡(jiǎn)單的 Hello World 來(lái)展示如何使用 Rust 語(yǔ)言編寫(xiě)驅(qū)動(dòng)代碼,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. }

與之對(duì)應(yīng)的 Makefile

  1. obj-m := hello_world.o

構(gòu)建:

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

之后就和使用普通的內(nèi)核模塊一樣,使用 insmod 工具或者 modprobe 工具加載就可以了。在使用體驗(yàn)上是沒(méi)有區(qū)別的。

module! { } 宏

這個(gè)宏可以被認(rèn)為是 Rust 內(nèi)核模塊的入口,因?yàn)樵谄渲卸x了一個(gè)內(nèi)核模塊所需的所有信息,包括:AuthorLicense、Description 等。其中最重要的是 type 字段,在其中需要指定內(nèi)核模塊結(jié)構(gòu)的名字。在這個(gè)例子中:

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

module_init() 與 module_exit()

在使用 C 編寫(xiě)的內(nèi)核模塊中,這兩個(gè)宏定義了模塊的入口函數(shù)與退出函數(shù)。在 Rust 編寫(xiě)的內(nèi)核模塊中,對(duì)應(yīng)的功能由 trait KernelModule 和 trait Drop 來(lái)實(shí)現(xiàn)。trait KernelModule 中定義 init() 函數(shù),會(huì)在模塊驅(qū)動(dòng)初始化時(shí)被調(diào)用;trait Drop 是 Rust 的內(nèi)置 trait,其中定義的 drop() 函數(shù)會(huì)在變量生命周期結(jié)束時(shí)被調(diào)用。

編譯與鏈接

所有的內(nèi)核模塊文件會(huì)首先被編譯成 .o 目標(biāo)文件,之后由內(nèi)核鏈接器將這些 .o 文件和自動(dòng)生成的模塊目標(biāo)文件 .mod.o 一起鏈接成為 .ko 文件。這個(gè) .ko 文件符合動(dòng)態(tài)庫(kù) ELF 文件格式,能夠被內(nèi)核識(shí)別并加載。

其他

完整的介紹 Rust 是如何被集成進(jìn)內(nèi)核的文章可以在 我的 Github 上找到,由于寫(xiě)的倉(cāng)促,可能存在一些不足,還請(qǐng)見(jiàn)諒。

作者簡(jiǎn)介

蘇子彬,阿里云 PAI 平臺(tái)開(kāi)發(fā)工程師,主要從事 Linux 系統(tǒng)及驅(qū)動(dòng)的相關(guān)開(kāi)發(fā),曾為 PAI 平臺(tái)編寫(xiě) FPGA 加速卡驅(qū)動(dòng)。 

 

責(zé)任編輯:龐桂玉 來(lái)源: Linux中國(guó)
相關(guān)推薦

2014-07-24 14:35:26

Linux內(nèi)核模塊

2018-06-19 09:07:57

Linux內(nèi)核模塊

2010-01-22 11:01:04

linux內(nèi)核模塊

2011-08-29 15:12:24

UbuntuLinux模塊

2023-05-08 08:05:42

內(nèi)核模塊Linux

2019-07-08 20:00:35

Linux內(nèi)核模塊

2010-04-12 11:19:47

編譯內(nèi)核模塊

2021-09-03 08:44:51

內(nèi)核模塊Linux社區(qū)

2022-05-14 17:01:21

開(kāi)源LinuxNVIDIA

2009-12-17 15:28:32

內(nèi)核模塊編譯

2021-03-11 12:19:39

Linux運(yùn)維Linux系統(tǒng)

2022-05-12 09:58:31

LinuxNVIDIA開(kāi)源

2018-05-14 09:48:45

Linux內(nèi)核模塊Kgotobed

2021-01-03 16:30:34

Rust編程語(yǔ)言

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架構(gòu)工具

2018-10-15 10:10:41

Linux內(nèi)核補(bǔ)丁

2024-04-16 08:09:36

JavapulsarAPI
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)