OS in Rust: An executable that runs on bare metal: Part-1

Reading Time: 4 minutes

This is the very first blog of the series that pertains to create a basic Operating System using Rust Programming Language.
The aim of this series is to learn and understand the basics of Operating System. Through this series, you will get some ideas about the internal components of Operating System and how they interact with each other.

Rust Programming Language for Beginners | Udemy

In this article, we will create a freestanding binary (an executable) that has the capability to run on bare metal. To create that executable we need to follow certain steps:

Steps to create a bare-metal executable:

  • Disable standard library
  • Define custom panic handler
  • Provide language items
  • Provide entry point
  • Build executable

Disable standard library

The very first question arises here is Why we are disabling Standard Library? So the reason to disable the standard library is, it depends on the Operating System for features like thread, files, and many more. Since we aim to write our Operating System and by default, all the Rust crates are linked to standard libraries, so we can not use any library that is dependent on Operating System.
To disable standard library we can use no_std attribute of Rust Programming. Like this:

#![no_std]

fn main() {
}

This is how we can use no_std attribute. Now we cannot use any feature provided by standard library in your project.
As we have excluded the standard library now our program won’t compile. It will give us an error like this:

This image has an empty alt attribute; its file name is screenshot-from-2020-09-19-13-53-44.png

This is because standard library provides its own panic handler, since we have removed the standard library so we need to define our custom panic handler and eh_personality language item.
Alright, let’s provide the panic handler first:

Define custom panic handler

The role of a panic handler is to define the function that should be invoked by the compiler when a panic occurs.
To define our custom panic handler, we need to use panic_handler attribute outside the function that will be used at the time of panic.

#![no_std]

use core::panic::PanicInfo;

#[panic_handler]
fn panic(_panic_info: &PanicInfo) -> ! {
    loop {}
}

Now we have provided our custom panic handler in our no_std environment. So to define this we have used, panic_handler attribute, a function named panic(), and PanicInfo as a parameter.
Let’s talk about the implementation components:
As we already discussed what the role of panic_handler is, now let’s talk about panic(), so this function will never return anything since the return type of this is never type i.e,! and it has an argument typed of PanicInfo which provides information about a panic in terms of file and line where the panic happened and the optional panic message, and we have used an indefinite loop because for now we just provided the custom panic handler.

Okay, we have provided the panic_handler, so our next step if to provide the language item.

Provide language item

In general terms, language items are a way for standard library to define types, traits, function, and other items which are required internally by the compiler. So here the missing language item is eh_personality.
eh_personality is required to create unwind information. Rust by default uses unwinding to run the destructors of all live stack variables in case of panic and unwinding requires some OS-specific libraries which should not be used in our case.

Okay, what should we do now???

So for now, if we disable the unwinding process then we can rid of this eh_personality error.

Disable unwinding process

For disabling the unwinding process, Rust provides an option to abort on panic. This feature disables the generation of unwinding symbol information. And we can this feature by simply adding a few instructions in our Cargo.toml file.
Like this:

[profile.dev]
panic = "abort"

[profile.release]
panic = "abort"

Now the eh_personality language item should no longer be required. Alright, we have fixed both panic_handler and language item error.
Now if we build our program we’ll get new error like this:

This image has an empty alt attribute; its file name is screenshot-from-2020-09-19-16-25-06.png

Our program requires the start language item which is used to define the entry point.
So let’s talk about the entry point first before providing the start language item to our binary.

In terms of programming, we think that the main function is the first function which is called when we run a program. But this statement is incorrect because initially the runtime (which is responsible for setting up an environment in which programs run) is called then the control goes to the main function.
In case of Rust, execution starts in a C runtime library called crt0, then this C runtime invokes the entry point of Rust runtime which is marked by the start language item, then the Rust runtime calls the main function.

And as of now, we don’t have access to both Rust runtime and crt0, so we need to define our own entry point. That we’ll implement in our next blog.

Stay tuned!!!

References:

If you want to read more content like this?  Subscribe Rust Times Newsletter and receive insights and latest updates, bi-weekly, straight into your inbox. Subscribe Rust Times Newsletter: https://bit.ly/2Vdlld7 .

This image has an empty alt attribute; its file name is screenshot-from-2020-06-08-11-00-35.png

Knoldus-blog-footer-image


Written by 

Pawan Singh Bisht is a Software Consultant at Knoldus Software LLP, having a strong experience of more than a year in the technology field. He has been well versed in the core implementation of Rust and Java. He loves to contribute towards the community which he attained from the community.