From dcf8b7767cd808716242dad024d9f6a61d1bf5e3 Mon Sep 17 00:00:00 2001 From: Philipp Oppermann Date: Sun, 8 Apr 2018 11:51:16 +0200 Subject: [PATCH] A dependency on compiler_builtins is now automatically injected (#426) --- Cargo.toml | 1 - Xargo.toml | 6 +++ .../posts/02-minimal-rust-kernel/index.md | 50 ++++++++----------- src/main.rs | 1 - 4 files changed, 27 insertions(+), 31 deletions(-) create mode 100644 Xargo.toml diff --git a/Cargo.toml b/Cargo.toml index b7c65090..f72dcd23 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,7 +4,6 @@ name = "blog_os" version = "0.2.0" [dependencies] -rlibc = "1.0" spin = "0.4.6" volatile = "0.2.3" diff --git a/Xargo.toml b/Xargo.toml new file mode 100644 index 00000000..5be4b76e --- /dev/null +++ b/Xargo.toml @@ -0,0 +1,6 @@ +[dependencies.core] +stage = 0 + +[dependencies.compiler_builtins] +features = ["mem"] +stage = 1 diff --git a/blog/content/second-edition/posts/02-minimal-rust-kernel/index.md b/blog/content/second-edition/posts/02-minimal-rust-kernel/index.md index eb85e39b..f36861e2 100644 --- a/blog/content/second-edition/posts/02-minimal-rust-kernel/index.md +++ b/blog/content/second-edition/posts/02-minimal-rust-kernel/index.md @@ -227,14 +227,14 @@ We can now build the kernel for our new target by passing the name of the JSON f ``` > RUST_TARGET_PATH=$(pwd) cargo build --target x86_64-blog_os -error[E0463]: can't find crate for `core` - | - = note: the `x86_64-blog_os` target may not be installed +error[E0463]: can't find crate for `core` OR +error[E0463]: can't find crate for `compiler_builtins` ``` -It failed! The error tells us that the Rust compiler no longer finds the core library. The [core library] is implicitly linked to all `no_std` crates and contains things such as `Result`, `Option`, and iterators. +It fails! The error tells us that the Rust compiler no longer finds the `core` or the `compiler_builtins` library. Both libraries are implicitly linked to all `no_std` crates. The [`core` library] contains basic Rust types such as `Result`, `Option`, and iterators, whereas the [`compiler_builtins` library] provides various lower level functions expected by LLVM, such as `memcpy`. -[core library]: https://doc.rust-lang.org/nightly/core/index.html +[`core` library]: https://doc.rust-lang.org/nightly/core/index.html +[`compiler_builtins` library]: https://github.com/rust-lang-nursery/compiler-builtins The problem is that the core library is distributed together with the Rust compiler as a _precompiled_ library. So it is only valid for supported host triples (e.g., `x86_64-unknown-linux-gnu`) but not for our custom target. If we want to compile code for other targets, we need to recompile `core` for these targets first. @@ -247,7 +247,18 @@ That's where [xargo] comes in. It is a wrapper for cargo that eases cross compil cargo install xargo ``` -Xargo depends on the rust source code, which we can install with `rustup component add rust-src`. +Xargo depends on the rust source code, which we can install with `rustup component add rust-src`. It also requires a file named `Xargo.toml` in our project directory that specifies which crates of the so-called _“sysroot”_ it should build. To build just the required `core` and `compiler_builtins` crates, we create the following `Xargo.toml`: + +```toml +[dependencies.core] +stage = 0 + +[dependencies.compiler_builtins] +features = ["mem"] +stage = 1 +``` + +The `stage` fields tell `Xargo` the order in which it should build things. The `compiler_builtins` crate requires the `core` crate itself, so it can only built in a second step after `core` has been compiled. So `core` is built in stage 0 and `compiler_builtins` is built in stage 1. The `mem` feature of `compiler_builtins` is required so that implementations for `memcpy`, `memset`, etc. are created. Xargo is “a drop-in replacement for cargo”, so every cargo command also works with `xargo`. You can do e.g. `xargo --help`, `xargo clean`, or `xargo doc`. The only difference is that the build command has additional functionality: `xargo build` will automatically cross compile the `core` library when compiling for custom targets. @@ -256,12 +267,14 @@ Let's try it: ```bash > RUST_TARGET_PATH=$(pwd) xargo build --target x86_64-blog_os Compiling core v0.0.0 (file:///…/rust/src/libcore) - Finished release [optimized] target(s) in 22.87 secs + Finished release [optimized] target(s) in 52.75 secs + Compiling compiler_builtins v0.1.0 (file:///…/rust/src/libcompiler_builtins) + Finished release [optimized] target(s) in 3.92 secs Compiling blog_os v0.1.0 (file:///…/blog_os) Finished dev [unoptimized + debuginfo] target(s) in 0.29 secs ``` -It worked! We see that `xargo` cross-compiled the `core` library for our new custom target and then continued to compile our `blog_os` crate. +It worked! We see that `xargo` cross-compiled the `core` and `compiler_builtin` libraries for our new custom target and then continued to compile our `blog_os` crate. Now we are able to build our kernel for a bare metal target. However, our `_start` entry point, which will be called by the boot loader, is still empty. So let's output something to screen from it. @@ -314,27 +327,6 @@ So we want to minimize the use of `unsafe` as much as possible. Rust gives us th [memory safety]: https://en.wikipedia.org/wiki/Memory_safety -We now have a simple “Hello World!” kernel. However, a more advanced kernel will still produce linker faults because the compiler tries to use some function normally provided by `libc`, most commonly `memcpy` and `memset`. To prevent these faults, we add an dependency on the [`rlibc`] crate, which provides implementations for the common `mem*` functions: - -[`rlibc`]: https://docs.rs/crate/rlibc - -```toml -# in Cargo.toml - -[dependencies] -rlibc = "1.0" -``` - -```rust -// in src/main.rs - -extern crate rlibc; -``` - -There is also the [`compiler_builtins`] crate that you should keep in mind. It provides Rust implementations for various other builtin functions, such as special floating point intrinsics. - -[`compiler_builtins`]: https://docs.rs/crate/compiler-builtins-snapshot - ### Creating a Bootimage Now that we have an executable that does something perceptible, it is time to turn it into a bootable disk image. As we learned in the [section about booting], we need a bootloader for that, which initializes the CPU and loads our kernel. diff --git a/src/main.rs b/src/main.rs index 301cc121..a7a24ded 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,7 +3,6 @@ #![no_std] // don't link the Rust standard library #![no_main] // disable all Rust-level entry points -extern crate rlibc; extern crate spin; extern crate volatile; #[macro_use]