Hi everyone, in today’s blog we are going to work on the bare metal environment in Rust. We will see that how we work with the no_std and no_main Rust environments. Working with no_main and no_std is a different way of programming.
In the previous blogs we have created a series to extract the readings of Gyroscope, Magnetometer, and Accelerometer all these applications basically work on the same bare metal environment. Now we are going to see the way things happen in such applications and what challenges we face while working in such a way.
As we are working with no_main and no_std Embedded Systems they make our task fast and reliable. Also, they are much smaller in size compared to traditional computers, which makes them compact and portable, and useful for mass production. Management of Embedded Systems is pretty easy, as elements used in their creation are cheap & long-lasting. Embedded Systems are also cost-effective.
The first step
The first step is to create a Rust executable that is not going to link with the standard library. This executable which is not linked to the standard library will help us work with the bare metal environment.
So not using a standard library means we are not using any Operating System here instead we are making our own OS which means we can’t use threads, files, heap memory, the network, or any other features requiring OS abstractions or specific hardware.
To create an OS kernel in Rust we need to make an executable that does not need require any OS to run and such an executable is known as freestanding or bare metal. We are not going to use many features of the standard library but we can use a few of them like iterators, closures, pattern matching, option and result, string formatting, and of course the ownership system.
Create a Project with no_std
Now the first thing we need to do is to create a new project using the command.
cargo new blog --bin
Now we need to make the biggest change in the application by cutting it from the Standard Library using #![no_std].
Okay now let’s try to build this code and see what error we face.
This is because the “println!” macro is part of the standard library and I guess now you know what we have done.
Okay after this let’s see what else errors we face on removing this “println!” macro. So after removing this printing statement and again building the application we got this.
The std library provides the panic attribute by default to the application but with the no_std application, we need to provide our own panic attribute.
Using this panic function we will be able to remove this error successfully.
So this function will get invoked whenever panic occurs and this will help in handling the panic so now when you build the application you will not see this error anymore.
This function contains the “divergent function ->” and “infinite loop” which means that this will not return anything nor it will end.
Okay now let’s move to the next error. This error was the error of “
eh_personality“. Before resolving this error we must know what this error means and why this occurs.
So this “eh_personality” is known as Language item where Language items are special functions and types that are required internally by the compiler.
We don’t require stack unwinding as it is a complicated process therefore we don’t want our OS to deal with such a task.
Let’s disable this unwinding process which is used by Rust by default. To do this we need to add a few lines in our “Cargo.toml“.
Now when you try to build the application it will get built without the “eh_personality” error but you will surely get another error which is.
Error “start” lang_item
Our program is missing the start language item, which defines the entry point. So this point is the first one that will get executed whenever the application runs. Therefore we must provide one starting point to our application.
Most other languages provide by default the main function as an entry point. In a typical Rust binary that links the standard library, execution starts in a C runtime library called crt0 (“C runtime zero”), which sets up the environment for a C application but as we are not using a standard library therefore we need to create our own entry point.
To tell the Rust compiler that we don’t want to use the normal entry point chain, we add the #![no_main] attribute. Working with no_main and no_std we can’t use the main method which comes from the standard library.
Put a few lines of code in your application to provide the entry function which also follows the same rule of not returning anything or ends.
We have used #[no_mangle] before the start function why so?
We want our function to get executed with our provided name here in this case it is _start. If we don’t use no_mangle then the compiler itself generates some cryptic
_ZN3blog_os4_start7hb173fedf945531caE symbol to give every function a unique name which we don’t want.
Link the Application
We are done with the coding part in our bare metal environment. Now let’s try to build the application. Did you successfully build your application? No? Why another error now?
Okay, this is the error now you are getting let’s work on this, and trust me this would be the last error.
Now as you know we are working differently. By default, Rust tries to build an executable that is able to run in your current system environment and we are working on our own made OS in a different environment so we need to build this application in a different way.
We need a target to build this application successfully and this target describes an embedded ARM system which means using such a target helps us in working with the embedded development. You can read more about such architecture and its target from here.
Use these two commands now to build the application successfully-
rustup target add thumbv7em-none-eabihf
cargo build --target thumbv7em-none-eabihf
We build the application successfully this time. You can see the working code and also If you face any problem while working on this then you can create an issue on this repository.
This was all from this blog. I hope you like this different type of working with no_main and no_std environment. Thanks for reading.
If you want to read more content like this? Subscribe to Rust Times Newsletter and receive insights and latest updates, bi-weekly, straight into your inbox. Subscribe to Rust Times Newsletter: https://bit.ly/2Vdlld7.