移除 runtime 依赖

对于大多数语言,他们都使用了 运行时系统(runtime system) ,这导致 main 并不是他们执行的第一个函数。

以 Rust 语言为例:一个典型的链接了标准库的 Rust 程序会首先跳转到 C runtime library 中的 crt0(C runtime zero) 进入 C runtime 设置 C 程序运行所需要的环境(比如:创建堆栈,设置寄存器参数等)。

然后 C runtime 会跳转到 Rust runtime 的 入口点(entry point) 进入 Rust runtime 继续设置 Rust 运行环境,而这个入口点就是被 start 语义项标记的。Rust runtime 结束之后才会调用 main 进入主程序。

C runtime 和 Rust runtime 都需要标准库支持,我们的程序无法访问。如果覆盖了 start 语义项,仍然需要 crt0,并不能解决问题。所以需要重写覆盖 crt0 入口点:

  1. // src/main.rs
  2. #![no_std] // don't link the Rust standard library
  3. #![no_main] // disable all Rust-level entry points
  4. use core::panic::PanicInfo;
  5. // This function is called on panic.
  6. #[panic_handler]
  7. fn panic(_info: &PanicInfo) -> ! {
  8. loop {}
  9. }
  10. #[no_mangle] // don't mangle the name of this function
  11. pub extern "C" fn _start() -> ! {
  12. // this function is the entry point, since the linker looks for a function named `_start` by default
  13. loop {}
  14. }

我们加上 #![no_main] 告诉编译器我们不用常规的入口点。

同时我们实现一个 _start 函数,并加上 #[no_mangle] 告诉编译器对于此函数禁用 name mangling ,确保编译器生成一个名为 _start 的函数,而非为了保证函数名字唯一性而生成的形如 _ZN3blog_os4_start7hb173fedf945531caE 乱码般的名字。由于 _start 是大多数系统的默认入口点名字,所以我们要确保它不会发生变化。

接着,我们使用 extern "C" 描述 _start 函数,这是 Rust 中的 FFI (Foreign Function Interface, 语言交互接口) 语法,表示此函数是一个 C 函数而非 Rust 函数。由于 _start 是作为 C runtime 的入口点,看起来合情合理。

返回值类型为 ! 表明这个函数不允许返回。由于这个函数被操作系统或 bootloader 直接调用,这样做是必须的。为了从入口点函数退出,我们需要通过 exit 系统调用,但我们目前还没法做到这一步,因此就让它在原地转圈吧。

由于程序会一直停在 C runtime crt0 的入口点,我们可以移除没用的 main 函数,并加上 ![no_main] 表示不用不使用普通的入口点那套理论。

再次 cargo build ,我们即将面对这一章中的最后一个错误!

cargo build error

linking with `cc` failed: exit code: 1

这个错误同样与 C runtime 有关,尽管 C runtime 的入口点已经被我们覆盖掉了,我们的项目仍默认链接 C runtime,因此需要一些 C 标准库 (libc) 的内容,由于我们禁用了标准库,我们也同样需要禁用常规的 C 启动例程。

cargo build 换成以下命令:

build passed

  1. $ cargo rustc -- -C link-arg=-nostartfiles
  2. Compiling os v0.1.0 ...
  3. Finished dev [unoptimized + debuginfo] target(s) in 4.87s

我们终于构建成功啦!虽然最后这个命令之后并不会用到,但是暂时看到了一个 success 不也很好吗?

构建得到的可执行文件位置放在 os/target/debug/os 中。

迄今为止的代码可以在这里找到,构建出现问题的话可以参考。