mirror of
https://github.com/phil-opp/blog_os.git
synced 2025-12-17 06:47:49 +00:00
Make cross-compile-* and set-up-gdb pages additional resourses
This commit is contained in:
46
blog/additional-resource/cross-compile-binutils.md
Normal file
46
blog/additional-resource/cross-compile-binutils.md
Normal file
@@ -0,0 +1,46 @@
|
||||
+++
|
||||
title = "Cross Compile Binutils"
|
||||
+++
|
||||
|
||||
The [GNU Binutils] are a collection of various binary tools such as `ld`, `as`, `objdump`, or `readelf`. These tools are platform-specific, so you need to compile them again if your host system and target system are different. In our case, we need `ld` and `objdump` for the x86_64 architecture.
|
||||
[GNU Binutils]: https://www.gnu.org/software/binutils/
|
||||
|
||||
## Building Setup
|
||||
First, you need to download a current binutils version from [here][download] \(the latest one is near the bottom). After extracting, you should have a folder named `binutils-2.X` where `X` is for example `25.1`. Now can create and switch to a new folder for building (recommended):
|
||||
[download]: ftp://sourceware.org/pub/binutils/snapshots
|
||||
|
||||
```bash
|
||||
mkdir build-binutils
|
||||
cd build-binutils
|
||||
```
|
||||
|
||||
## Configuration
|
||||
We execute binutils's `configure` and pass a lot of arguments to it (replace the `X` with the version number):
|
||||
|
||||
```bash
|
||||
../binutils-2.X/configure --target=x86_64-elf --prefix="$HOME/opt/cross" \
|
||||
--disable-nls --disable-werror \
|
||||
--disable-gdb --disable-libdecnumber --disable-readline --disable-sim
|
||||
```
|
||||
- The `target` argument specifies the the x86_64 target architecture.
|
||||
- The `prefix` argument selects the installation directory, you can change it if you like. But be careful that you do not overwrite your system's binutils.
|
||||
- The `disable-nls` flag disables native language support (so you'll get the same english error messages). It also reduces build dependencies.
|
||||
- The `disable-werror` turns all warnings into errors.
|
||||
- The last line disables features we don't need to reduce compile time.
|
||||
|
||||
## Building it
|
||||
Now we can build and install it to the location supplied as `prefix` (it will take a while):
|
||||
|
||||
```bash
|
||||
make
|
||||
make install
|
||||
```
|
||||
Now you should have multiple `x86_64-elf-XXX` files in `$HOME/opt/cross/bin`.
|
||||
|
||||
## Adding it to the PATH
|
||||
To use the tools from the command line easily, you should add the `bin` folder to your PATH:
|
||||
|
||||
```bash
|
||||
export PATH="$HOME/opt/cross/bin:$PATH"
|
||||
```
|
||||
If you add this line to your e.g. `.bashrc`, the `x86_64-elf-XXX` commands are always available.
|
||||
47
blog/additional-resource/cross-compile-libcore.md
Normal file
47
blog/additional-resource/cross-compile-libcore.md
Normal file
@@ -0,0 +1,47 @@
|
||||
+++
|
||||
title = "Cross Compiling: libcore"
|
||||
+++
|
||||
|
||||
So you're getting an ``error: can't find crate for `core` [E0463]`` when using `--target x86_64-unknown-linux-gnu`. That means that you're not running Linux or not using using a x86_64 processor.
|
||||
|
||||
**If you have an x86_64 processor and want a quick fix**, try it with `x86_64-pc-windows-gnu` or `x86_64-apple-darwin` (or simply omit the explicit `--target`).
|
||||
|
||||
The idiomatic alternative and the only option for non x86_64 CPUs is described below. Note that you need to [cross compile binutils], too.
|
||||
[cross compile binutils]: /cross-compile-binutils.html
|
||||
|
||||
## Libcore
|
||||
The core library is a dependency-free library that is added implicitly when using `#![no_std]`. It provides basic standard library features like Option or Iterator. The core library is installed together with the rust compiler (just like the std library). But the installed libcore is specific to your architecture. If you aren't working on x86_64 Linux and pass `‑‑target x86_64‑unknown‑linux‑gnu` to cargo, it can't find a x86_64 libcore. To fix this, you can either download it or build it using cargo.
|
||||
|
||||
## Download it
|
||||
You need to download the 64-bit Linux Rust build corresponding to your installed nightly. You can either just update to the current nightly and download the current nightly source [here][Rust downloads]. Or you retrieve your installed version through `rustc --version` and search the corresponding subfolder [here](http://static.rust-lang.org/dist/).
|
||||
[Rust downloads]: https://www.rust-lang.org/downloads.html
|
||||
|
||||
After extracting it and you need to copy the `x86_64-unknown-linux-gnu` folder in `rust-std-x86_64-unknown-linux-gnu/lib/rustlib` to your local Rust installation. For multirust, the right target folder is `~/.multirust/toolchains/nightly/lib/rustlib`. That's it!
|
||||
|
||||
## Build it using cargo
|
||||
The alternative is to use cargo to build libcore. But this variant has one big disadvantage: You have to modify each crate you depend on because it needs to use the same libcore. So you can't just add a crates.io dependency anymore, you need to fork and modify it first.
|
||||
|
||||
If you want to build libcore anyway, you need its source code. You can either clone the [rust repository] \(makes updates easy) or manually [download the Rust source][Rust downloads] \(faster and less memory).
|
||||
[rust repository]: https://github.com/rust-lang/rust
|
||||
|
||||
Now we create a new cargo project named `core`, but delete its `src` folder:
|
||||
|
||||
```bash
|
||||
cargo new core
|
||||
rm -r core/src
|
||||
```
|
||||
|
||||
Then we create a symbolic link named `src` to the `rust/src/libcore` of the Rust source code:
|
||||
|
||||
```bash
|
||||
ln -s ../rust/src/libcore core/src
|
||||
```
|
||||
|
||||
To use our new libcore crate (instead of the one installed together with rust) in our OS, we need to add it as a local dependency in the `Cargo.toml`:
|
||||
|
||||
```toml
|
||||
...
|
||||
[dependencies.core]
|
||||
path = "core"
|
||||
```
|
||||
Now cargo compiles libcore for all Rust targets automatically.
|
||||
74
blog/additional-resource/set-up-gdb.md
Normal file
74
blog/additional-resource/set-up-gdb.md
Normal file
@@ -0,0 +1,74 @@
|
||||
+++
|
||||
title = "Set Up GDB"
|
||||
+++
|
||||
|
||||
There are a lot of things that can go wrong when developing an OS. So it's a good idea to add a debugger to our toolset, which allows us to set breakpoints and examine variables. We will use [GDB](https://www.gnu.org/software/gdb/) as QEMU supports it out of the box.
|
||||
|
||||
### QEMU parameters
|
||||
To make QEMU listen for a gdb connection, we add the `-s` flag to the `run` target in our Makefile:
|
||||
|
||||
```make
|
||||
run: $(iso)
|
||||
@qemu-system-x86_64 -cdrom $(iso) -s
|
||||
```
|
||||
This allows us to connect a debugger at any time, for example to investigate why a panic occurred.
|
||||
|
||||
To wait for a debugger connection on startup, we add a `debug` target to the Makefile:
|
||||
|
||||
```make
|
||||
debug: $(iso)
|
||||
@qemu-system-x86_64 -cdrom $(iso) -s -S
|
||||
```
|
||||
It is identical to the `run` target except for the additional `-S` flag. This flag causes QEMU to freeze on startup and wait until a debugger is connected. Now it _should_ be possible to connect gdb.
|
||||
|
||||
### The annoying issue
|
||||
Unfortunately gdb has an issue with the switch to long mode. If we connect when the CPU is already in long mode, everything works fine. But if we use `make debug` and thus connect right at the start, we get an error when we set a breakpoint in 64-bit mode:
|
||||
|
||||
```
|
||||
Remote 'g' packet reply is too long: [a very long number]
|
||||
```
|
||||
This issue is known [since 2012][gdb issue patch] but it is still not fixed. Maybe we find the reason in the [issue thread][gdb issue thread]:
|
||||
|
||||
[gdb issue patch]: http://www.cygwin.com/ml/gdb-patches/2012-03/msg00116.html
|
||||
[gdb issue thread]: https://sourceware.org/bugzilla/show_bug.cgi?id=13984#c11
|
||||
|
||||
> from my (limited) experience, unless you ping the gdb-patches list weekly, this patch is more likely to remain forgotten :-)
|
||||
|
||||
Pretty frustrating, especially since the patch is [very small][gdb patch commit].
|
||||
|
||||
[gdb patch commit]: https://github.com/phil-opp/binutils-gdb/commit/9e88c451844ad38bb82fe77d1f388c87c41b4520
|
||||
|
||||
### Building the patched GDB
|
||||
So the only way to use gdb with `make debug` is to build a modified gdb version that includes the patch. I created a repository with the patched GDB to make this easy. Just follow [the build instructions].
|
||||
|
||||
[the build instructions]: https://github.com/phil-opp/binutils-gdb#gdb-for-64-bit-rust-operating-systems
|
||||
|
||||
### Connecting GDB
|
||||
Now you should have a `rust-os-gdb` subfolder. In its `bin` directory you find the `gdb` executable and the `rust-gdb` script, which [improves rendering of Rust types]. To make it easy to use it for our OS, we add a `make gdb` target to our Makefile:
|
||||
|
||||
[improves rendering of Rust types]: https://michaelwoerister.github.io/2015/03/27/rust-xxdb.html
|
||||
|
||||
```make
|
||||
gdb:
|
||||
@rust-os-gdb/bin/rust-gdb "build/kernel-x86_64.bin" -ex "target remote :1234"
|
||||
```
|
||||
It loads the debug information from our kernel binary and connects to the `localhost:1234` port, on which QEMU listens by default.
|
||||
|
||||
### Using GDB
|
||||
After connecting to QEMU, you can use various gdb commands to control execution and examine data. All commands can be abbreviated as long they are still unique. For example, you can write `c` or `cont` instead of `continue`. The most important commands are:
|
||||
|
||||
- `help` or `h`: Show the help.
|
||||
- `break` or `b`: Set a breakpoint. It possible to break on functions such as `rust_main` or on source lines such as `lib.rs:42`. You can use tab for autocompletion and omit parts of the path as long it's still unique. To modify breakpoints, you can use `disable`, `enable`, and `delete` plus the breakpoint number.
|
||||
- `continue` or `c`: Continue execution until a breakpoint is reached.
|
||||
- `next` or `n`: Step over the current line and break on the next line of the function. Sometimes this doesn't work in Rust OSes.
|
||||
- `step` or `s`: Step into the current line, i.e. jump to the called function. Sometimes this doesn't work in Rust OSes.
|
||||
- `list` or `l`: Shows the source code around the current position.
|
||||
- `print` or `p`: Prints the value of a variable. You can use Cs `*` and `&` operators. To print in hexadecimal, use `p/x`.
|
||||
- `tui enable`: Enables the text user interface, which provides a graphical interface (see below). To disable it again, run `tui disable`.
|
||||
|
||||

|
||||
|
||||
Of course there are many more commands. Feel free to send a PR if you think this list is missing something important. For a more complete GDB overview, check out [Beej's Quick Guide][bggdb] or the [website for Harvard's CS161 course][CS161].
|
||||
|
||||
[bggdb]: http://beej.us/guide/bggdb/
|
||||
[CS161]: http://www.eecs.harvard.edu/~cs161/resources/gdb.html
|
||||
Reference in New Issue
Block a user