Files
rust-based-os-comp2022/guide/source/chapter1/2remove-std.rst
2022-07-17 10:48:39 +08:00

183 lines
5.8 KiB
ReStructuredText
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
.. _term-remove-std:
移除标准库依赖
==========================
.. toctree::
:hidden:
:maxdepth: 5
由于后续实验需要 ``rustc`` 编译器缺省生成RISC-V 64的目标代码所以我们首先要给 ``rustc`` 添加一个target : ``riscv64gc-unknown-none-elf`` 。这可通过如下命令来完成:
.. code-block:: bash
$ rustup target add riscv64gc-unknown-none-elf
然后在 ``os`` 目录下新建 ``.cargo`` 目录,并在这个目录下创建 ``config`` 文件,输入如下内容:
.. code-block:: toml
# os/.cargo/config
[build]
target = "riscv64gc-unknown-none-elf"
这将使 cargo 工具在 os 目录下默认会使用 riscv64gc-unknown-none-elf 作为目标平台。
这种编译器运行的平台x86_64与可执行文件运行的目标平台不同的情况称为 **交叉编译** (Cross Compile)。
移除 println! 宏
----------------------------------
我们在 ``main.rs`` 的开头加上一行 ``#![no_std]``
告诉 Rust 编译器不使用 Rust 标准库 std 转而使用核心库 core。重新编译报错如下
.. error::
.. code-block:: console
$ cargo build
Compiling os v0.1.0 (/home/shinbokuow/workspace/v3/rCore-Tutorial-v3/os)
error: cannot find macro `println` in this scope
--> src/main.rs:4:5
|
4 | println!("Hello, world!");
| ^^^^^^^
println! 宏是由标准库 std 提供的,且会使用到一个名为 write 的系统调用。
无论如何,我们先将这行代码注释掉。
提供语义项 panic_handler
----------------------------------------------------
.. error::
.. code-block:: console
$ cargo build
Compiling os v0.1.0 (/home/shinbokuow/workspace/v3/rCore-Tutorial-v3/os)
error: `#[panic_handler]` function required, but not found
标准库 std 提供了 Rust 错误处理函数 ``#[panic_handler]``,其大致功能是打印出错位置和原因并杀死当前应用。
但核心库 core 并没有提供这项功能,得靠我们自己实现。
新建一个子模块 ``lang_items.rs``,在里面编写 panic 处理函数,通过标记 ``#[panic_handler]`` 告知编译器采用我们的实现:
.. code-block:: rust
// os/src/lang_items.rs
use core::panic::PanicInfo;
#[panic_handler]
fn panic(_info: &PanicInfo) -> ! {
loop {}
}
在把 ``panic_handler`` 配置在单独的文件 ``os/src/lang_items.rs``需要在os/src/main.rs文件中添加以下内容才能正常编译整个软件
.. code-block:: rust
// os/src/main.rs
#![no_std]
mod lang_items;
// ... other code
注意panic 处理函数的函数签名需要一个 ``PanicInfo`` 的不可变借用作为输入参数,它在核心库中得以保留,这也是我们第一次与核心库打交道。之后我们会从 ``PanicInfo`` 解析出错位置并打印出来然后杀死应用程序。但目前编译出的简单OS在运行时如果遇到错误什么都不做只在原地 ``loop``
移除 main 函数
-----------------------------
重新编译,又有了新错误:
.. error::
.. code-block::
$ cargo build
Compiling os v0.1.0 (/home/shinbokuow/workspace/v3/rCore-Tutorial-v3/os)
error: requires `start` lang_item
编译器提醒我们缺少一个名为 ``start`` 的语义项。
``start`` 语义项代表了标准库 std 在执行应用程序之前需要进行的一些初始化工作。由于我们禁用了标准库,编译器也就找不到这项功能的实现了。
``main.rs`` 的开头加入设置 ``#![no_main]`` 告诉编译器我们没有一般意义上的 ``main`` 函数,
并将原来的 ``main`` 函数删除。这样编译器也就不需要考虑初始化工作了。
.. code-block:: console
$ cargo build
Compiling os v0.1.0 (/home/shinbokuow/workspace/v3/rCore-Tutorial-v3/os)
Finished dev [unoptimized + debuginfo] target(s) in 0.06s
至此,我们终于移除了所有标准库依赖。目前的主要代码包括 ``main.rs````lang_items.rs`` ,大致内容如下:
.. code-block:: rust
// os/src/main.rs
#![no_main]
#![no_std]
mod lang_items;
// ... other code
// os/src/lang_items.rs
use core::panic::PanicInfo;
#[panic_handler]
fn panic(_info: &PanicInfo) -> ! {
loop {}
}
分析被移除标准库的程序
-----------------------------
首先安装 cargo-binutils 工具集:
.. code-block:: console
$ cargo install cargo-binutils
$ rustup component add llvm-tools-preview
我们可以通过各种工具来分析目前的程序:
.. code-block:: console
[文件格式]
$ file target/riscv64gc-unknown-none-elf/debug/os
target/riscv64gc-unknown-none-elf/debug/os: ELF 64-bit LSB executable, UCB RISC-V, ......
[文件头信息]
$ rust-readobj -h target/riscv64gc-unknown-none-elf/debug/os
File: target/riscv64gc-unknown-none-elf/debug/os
Format: elf64-littleriscv
Arch: riscv64
AddressSize: 64bit
......
Type: Executable (0x2)
Machine: EM_RISCV (0xF3)
Version: 1
Entry: 0x0
......
}
[反汇编导出汇编程序]
$ rust-objdump -S target/riscv64gc-unknown-none-elf/debug/os
target/riscv64gc-unknown-none-elf/debug/os: file format elf64-littleriscv
通过 ``file`` 工具对二进制程序 ``os`` 的分析可以看到,它好像是一个合法的 RV64 执行程序,
``rust-readobj`` 工具告诉我们它的入口地址 Entry 是 ``0``
再通过 ``rust-objdump`` 工具把它反汇编,没有生成任何汇编代码。
可见,这个二进制程序虽然合法,但它是一个空程序,原因是缺少了编译器规定的入口函数 ``_start``
从下一节开始,我们将着手实现本节移除的、由用户态执行环境提供的功能。
.. note::
本节内容部分参考自 `BlogOS 的相关章节 <https://os.phil-opp.com/freestanding-rust-binary/>`_