rCore Labs

TL;DR

这篇博客用于记录探索rCore kernel的设计哲学和学习遇到值得思考的内容

对这个实验感兴趣的原因也是Rust是第一个走进Linux项目的现代编程语言(虽然目前大部分仍在驱动程序环节)

对于内核本身,现代编程语言相较于C,也是有很多需要重新设计和考虑的情况

Github Repo

rCore vs xv6

由于语言的不同,两者在设计思路上也会有区别

自定义section

自定义sections绝对是编译/构建工程中的一个绝佳方案,它可以让构建过程脱离对于Makefile的依赖,而Rust的理念是通过Cargo来自动化构建

过去对于Makefile强依赖的原因是地址顺序,由于kernel离开ROM的时候,pc需要刚好在0x80000000上执行_entry符号中的代码

这也就意味着在链接的时候,需要在Makefile和链接器脚本进行配合

(如今的xv6已经通过优化链接脚本脱离了对于Makefile的依赖)

kernel.ld

可以看到已经在kernel.ld中显式说明了要先处理entry.o,并将其放置到0x80000000上

实现了解耦

但是如果在ld脚本中没有显示说明,使用了通用的.text写法,例如:

.text : {
    *(.text .text.*)
}

这样就会依赖Makefile中传入.o文件的顺序

同时我们可以自己实践查看Rust是如何将函数编译时分为不同section的

#[inline(never)] // disable inline
pub fn foo() {
    println!("Hello from foo!");
}

#[inline(never)]
pub fn bar() {
    println!("Hello from bar!");
}

fn main() {
    foo();
    bar();
}
rustc --emit=obj main.rs
objdump -h main.o

func-section

这样就可以看到对应的section

总结优势:

  1. 构建工具解耦,不依赖Unix Makefile

  2. 可以适配LLVM + LTO(链接时优化)

  3. 符合Rust哲学 -> 显示优于隐式

LLVM and LTO

这个可以单开一个进行讲解

tsoding曾聊到stb库,也就是单头文件库的概念

很多人在这里曾表示过怀疑,认为这种情况只能适用于小型库,但实际上,它可以扩展为任意复杂度

sqlite值得被称为世界上最伟大的数据库之一,它提供了amalgamation版本

将所有文件合并为两个.c文件

sqlite

这样做的好处是可以让编译器根据上下文,最大限度地利用编译器优化,也可以实现单头文件调用sqlite api

当然缺点是编译速度相对慢

llvm在这里同理,当编译器生成ir后,llvm将所有文件的ir合并在一起,这样就实现了这样的效果

如今结合LTO,使用自定义section可以实现跨模块函数内联, 全程序死代码消除, 虚函数去虚拟化

⋅˚₊‧ ⌜ on this page ⌟ ‧₊˚ ⋅

recent-work

ELF格式解析

TL;DR 一个 ELF 文件同时被四个角色读写:编译器产出它、链接器改造它、内核加载器消费它、工具与攻击者审视它。这四个读者看的是同一坨字节,但需求完全不同。ELF 的解法是把文件切成两套正交的索引表: Program Header Table(段视图)——给加载器看,描述“运 …

Read more →

NEMU RISC-V32 指令模式匹配与汇编级优化

TL;DR 本文沿着一条「先问为什么,再看怎么做」的线索,拆开 NEMU 的 RISC-V32 指令解码:从「怎么知道当前是哪条指令」这个问题出发,引出模式字符串,再手推 pattern_decode 如何把它变成 key/mask/shift,最后贴出宿主机 Intel 汇编, …

Read more →