Skip to content

Rust automatically injects a dependency on compiler_builtins now #426

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Apr 8, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ name = "blog_os"
version = "0.2.0"

[dependencies]
rlibc = "1.0"
spin = "0.4.6"
volatile = "0.2.3"

Expand Down
6 changes: 6 additions & 0 deletions Xargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[dependencies.core]
stage = 0

[dependencies.compiler_builtins]
features = ["mem"]
stage = 1
50 changes: 21 additions & 29 deletions blog/content/second-edition/posts/02-minimal-rust-kernel/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand All @@ -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.

Expand All @@ -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.

Expand Down Expand Up @@ -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.

Expand Down
1 change: 0 additions & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down