『7x24小时有问必答』
            Rust已正式进入Linux内核主线,成为继C之后第二门内核官方支持语言。本文用3分钟,从Rust核心特性、与C语言对比、到手把手带你写一个真正的Linux内核模块(insmod → dmesg看日志 → rmmod),帮你快速理解Rust凭什么能进内核主线。所有代码已在Ubuntu 24.04(Kernel 6.17)验证通过,可直接复制运行。

为什么要花几分钟了解Rust

Linux内核已正式支持Rust

2022年Linux 6.1内核首次合并Rust支持,2026年Rust内核驱动框架趋于成熟。这意味着:写Linux驱动,你有了C之外的选择。

底层开发的三大痛点,Rust全解决

痛点
C语言现状
Rust方案
内存泄漏
手动malloc/free,忘记释放就泄漏
所有权机制,编译期自动释放
野指针
释放后继续访问,运行时才崩溃
借用检查器,编译期杜绝
数据竞争
多线程共享变量无保护,结果不确定
所有权+Send/Sync trait,编译期防止

零成本抽象:不牺牲性能的安全

Rust没有垃圾回收器(GC),所有安全检查在编译期完成,运行时开销为零。这意味着:Rust的安全,不需要用性能换。

Rust核心特性

特性一:所有权——不用GC也能内存安全

Rust所有权只有三条规则:
每个值只有一个所有者
赋值会转移所有权(Move语义)
所有者离开作用域,值自动释放
fn  main() {

       let  s1  =  String::from("hello");

       let  s2  = s1;                 // s1的所有权转移给s2

       // println!("{}", s1); // 编译报错!s1已失效

       println!("{}", s2);      // 正常

}

对比C语言的等价操作:
char  *s1 =  malloc(6);

strcpy(s1,  "hello");

char  *s2 = s1;           // 两个指针指向同一块内存

free(s1);

printf("%s", s2);      // 野指针!运行时才崩溃

Rust在编译期就阻止了这类错误,而不是等到运行时才崩溃。

特性二:借用与引用——灵活访问不丧失安全

fn  calculate_length(s: &String)  ->  usize  {   // 不可变借用

      s.len()

}

fn  append_world(s: &mut  String) {                 // 可变借用

      s.push_str(", world");

}

借用规则(编译期强制):
同一时间只能有一个可变引用,或多个不可变引用
可变与不可变引用不能共存
两条规则就够了,编译器帮你拦住所有数据竞争。

特性三:Option与Result——告别空指针和错误码

C语言用NULL和返回值表示错误,Rust用类型系统强制处理:
// Option:替代null

let  score:  Option<i32> =  Some(85);

let  no_score:  Option<i32> =  None;

// 必须显式处理"无值"的情况

match  score {

       Some(s) =>  println!("成绩: {}", s),

       None  =>  println!("无成绩"),

}

// Result:替代错误码

fn  divide(a:  f64, b:  f64)  ->  Result<f64,  String> {

       if  b ==  0.0  {

             Err(String::from("除数不能为0"))

      }  else  {

             Ok(a / b)

      }

}

// ?运算符:简化错误传播

fn  complex_calc()  ->  Result<f64,  String> {

       let  a  =  divide(10.0,  2.0)?;     // 出错直接返回

       let  b  =  divide(a,  3.0)?;

       Ok(b *  2.0)

}

特性四:Trait——零成本的多态

trait  Shape  {

       fn  area(&self)  ->  f64;

       fn  name(&self)  ->  &str;

}

struct  Circle  { radius:  f64  }

struct  Rectangle  { width:  f64, height:  f64  }

impl  Shape  for  Circle  {

       fn  area(&self)  ->  f64  { std::f64::consts::PI *  self.radius *  self.radius }

       fn  name(&self)  ->  &str  {  "圆形"  }

}

impl  Shape  for  Rectangle  {

       fn  area(&self)  ->  f64  {  self.width *  self.height }

       fn  name(&self)  ->  &str  {  "矩形"  }

}

泛型在编译期展开(单态化),运行时没有虚函数表开销——这就是零成本抽象:
// 编译器自动生成具体函数,无运行时分发

fn  get_larger<t: [="" span]partialord[="" span][="" span]="">(a: T, b: T)  ->  T {

       if  a > b { a }  else  { b }

}

// 编译后等价于:

// fn get_larger_i32(a: i32, b: i32) -> i32 { ... }

// fn get_larger_f64(a: f64, b: f64) -> f64 { ... }

特性五:并发安全——编译期防止数据竞争

use  std::sync::{Arc, Mutex};

use  std::thread;

fn  main() {

       let  counter  = Arc::new(Mutex::new(0));

       let  mut  handles  =  vec![];

       for  i  in  0..5  {

             let  counter_clone  = Arc::clone(&counter);

             let  handle  = thread::spawn(move  || {

                   let  mut  num  = counter_clone.lock().unwrap();

                  *num +=  1;

                   println!("线程 {} 执行,当前值: {}", i, *num);

            });

            handles.push(handle);

      }

       for  handle  in  handles {

            handle.join().unwrap();

      }

       println!("最终计数: {}", *counter.lock().unwrap());  // 确定是5

}

对比C语言的数据竞争:
int  shared_data =  0;

void*  increment(void* arg)  {

       for  (int  i =  0; i <  100000; i++) {

            shared_data++;   // 数据竞争!结果不确定

      }

       return  NULL;

}

Rust的Arc<mutex<t>>在类型层面强制线程安全——不加锁,代码编译不过。

Rust vs C:核心对比

维度
C语言
Rust
内存管理
手动malloc/free
所有权自动释放
空指针
运行时崩溃(段错误)
Option类型,编译期杜绝
错误处理
返回错误码,容易忽略
Result类型,强制处理
数据竞争
无保护,结果不确定
编译期阻止
泛型
宏或void*,类型不安全
编译期单态化,类型安全
FFI互操作
—
可调用C函数,无缝对接
运行时开销
无
无(零成本抽象)
学习曲线
低
较高(借用检查器)
关键结论:Rust的安全不牺牲性能,代价是编译期的学习成本。

完整Demo:Rust Linux内核驱动

这个Demo展示Rust如何写一个真实的Linux内核模块,通过C包装层调用Rust代码。

项目结构

rust_linux_driver/

├── .cargo/

│    └── config.toml     # Rust编译配置(static relocation)

├── Cargo.toml            # Rust项目配置

├── src/

│    └── lib.rs            # Rust核心代码

├── wrapper.c              # C语言包装层

└── Makefile               # 编译脚本

1. Cargo.toml

[package]

name = "rust_linux_driver"

version = "0.1.0"

edition = "2021"

[lib]

crate-type = ["staticlib"]

[profile.release]

panic = "abort"

opt-level = "s"

2. src/lib.rs

#![no_std]// 内核环境不支持标准库

use  core::ffi::c_int;

const  HELLO_MSG: &[u8] =  b"[rust_driver] Hello Rust Linux Kernel Driver!\n\0";

const  BYE_MSG: &[u8] =  b"[rust_driver] Goodbye Rust Linux Driver!\n\0";

#[no_mangle]

pub  extern  "C"  fn  rust_init_module()  ->  c_int {

       unsafe  {

            _printk(HELLO_MSG.as_ptr()  as  *const  u8);

      }

       0

}

#[no_mangle]

pub  extern  "C"  fn  rust_cleanup_module() {

       unsafe  {

            _printk(BYE_MSG.as_ptr()  as  *const  u8);

      }

}

extern  "C"  {

       fn  _printk(fmt: *const  u8, ...)  ->  c_int;   // 内核导出的是_printk

}

#[panic_handler]

fn  panic(_info: &core::panic::PanicInfo)  ->  ! {

       loop  {}

}

关键:内核导出的符号是  _printk  而非  printk(printk  是C宏),Rust FFI必须声明为  _printk。

3. .cargo/config.toml(Rust编译配置)

[build]

rustflags = ["-C", "relocation-model=static"]

关键:relocation-model=static  避免生成内核不支持的 GOTPCREL 重定位。

4. wrapper.c

#include  <linux module.h="">

#include  <linux kernel.h="">

extern  int  rust_init_module(void);

extern  void  rust_cleanup_module(void);

int  init_module(void)

{

      pr_info("C wrapper: calling Rust init\n");

       return  rust_init_module();

}

void  cleanup_module(void)

{

      pr_info("C wrapper: calling Rust cleanup\n");

      rust_cleanup_module();

}

MODULE_LICENSE("GPL");

MODULE_AUTHOR("linuxros");

MODULE_DESCRIPTION("Rust Linux Kernel Driver with linuxROS");

5. Makefile

obj-m += rust_linux_driver.o

rust_linux_driver-objs := wrapper.o rust_driver.o

KERNELDIR ?= /lib/modules/$(shell  uname -r)/build

PWD :=  $(shell  pwd)

all:

   rustc --edition 2021 --crate-type staticlib --emit=obj \

      src/lib.rs -o rust_driver.o \

      --target x86_64-unknown-none \

      -C relocation-model=static -C panic=abort

$(MAKE)  -C  $(KERNELDIR)  M=$(PWD)  modules

clean:

$(MAKE)  -C  $(KERNELDIR)  M=$(PWD)  clean

   rm -f rust_driver.o *.o

关键:用  rustc --emit=obj  直接生成  .o  文件,避免  cargo build  静态库中  compiler_builtins  的 GOTPCREL 重定位问题。

6. 编译、加载、测试

#  安装依赖

sudo apt install -y build-essential linux-headers-$(uname -r) llvm clang lld libelf-dev

rustup target add x86_64-unknown-none

#  
编译

make

#  
加载驱动

sudo insmod rust_linux_driver.ko

sudo dmesg | tail -n 5

#  输出: [rust_driver] Hello Rust Linux Kernel Driver!

#  
卸载驱动

sudo rmmod rust_linux_driver

sudo dmesg | tail -n 5

#  输出: [rust_driver] Goodbye Rust Linux Driver!

Demo技术要点

要点
说明
#![no_std]
禁用标准库,内核环境不支持std
_printk
内核导出符号为  _printk,非  printk(C宏)
relocation-model=static
避免 GOTPCREL 重定位,内核模块加载器不支持
--emit=obj
直接编译为  .o  目标文件,跳过静态库提取
#[no_mangle]
防止函数名被编译器混淆,C可调用
wrapper.c
C包装层,桥接内核模块框架与Rust代码

总结

Rust继承了C的零开销理念,补上了内存安全和并发安全的短板:
内存安全:所有权机制在编译期杜绝泄漏、野指针、重复释放
并发安全:类型系统在编译期防止数据竞争
零成本抽象:安全不牺牲性能,无GC无运行时开销
内核就绪:Linux 6.1+官方支持,C包装层可兼容旧内核
生态成熟:Cargo包管理、Clippy检查、Rustfmt格式化
C语言在底层开发领域用了40年,Rust可能是下一个40年的答案。
再往远想:AI写代码的能力还在涨,LLVM和GCC的后端本来就是IR到二进制——哪天AI能从自然语言直接出正确的机器码,语言本身就退居二线了,C和Rust都是中间态。但那是以后的事。现在,编译器还得干活,类型系统还得兜底,Rust是今天安全+性能最务实的选择。
</linux></linux></mutex<t></t:>

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

上一主题上一主题         下一主题下一主题
QQ手机版小黑屋粤ICP备17165530号

关于我们·投诉举报· 用户帮助· 联系我们 · 本站服务 · 版权声明· 隐私政策 · 投搞指南

法律保护:PLC技术网,plcjs.com,plcjs.net等字样
Copyright 2010-2030. All rights reserved. 


微信公众号二维码 抖音二维码 百家号二维码 今日头条二维码哔哩哔哩二维码