Writing an OS in Rust. Setting up the environment. Binary for "bare" iron

Setting up the environment. Naked binary, or Executable without main ()



The first step in writing your own OS is creating a binary that does not depend on standard libraries, this makes it possible to run code without an OS - we are writing our own.



The original blog is being developed on GitHub . Leave your comments to the original on the Issues page of the repository above, and to the translation - in PM, comments or here . The code written in this article is contained in post-01.



Introduction



In order to write our own OS, we need code that does not depend on libraries or functions of another operating system. This means that we cannot use threads, files, heap memory, networking, terminal output, and so on. But this can be overcome by writing your own OS and drivers.



We cannot use most of the Rust standard library , but there are also many functions that we can use. For example, iterators , closures , pattern matching , Option and Result , string formatting , and of course the concept of ownership . This will allow you to write your kernel in a high-level style without worrying about undefined behavior or memory safety .



This article explains how to create a stand-alone executable file and why you need it. If you just need an example, you can scroll to the Conclusion section.



Disabling the standard library



, , , .. : libc, . , , . no_std.



Cargo. :



cargo new os-in-rust --bin --edition 2018


os-in-rust ( ), . --bin , , , . --edition 2018 , Rust 2018. Cargo :



os-in-rust
โ”œโ”€โ”€ Cargo.toml
โ””โ”€โ”€ src
    โ””โ”€โ”€ main.rs


Cargo.toml : , , . src/main.rs , , . cargo build, target/debug.



no_std



. no_std:



// main.rs
#![no_std]

fn main() {
  println!("Hello, world!");
}


, :



error: cannot find macro `println!` in this scope
 --> src/main.rs:4:5
  |
4 |     println!("Hello, world!");
  |     ^^^^^^^


, println โ€” Rust, . , . , , . :(



:



// main.rs
#![no_std]

fn main() {}


> cargo build
error: `#[panic_handler]` function required, but not found
error: language item required, but not found: `eh_personality`


panic!()



panic_handler , , ( panic!()). , no_std :



// main.rs

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


PanicInfo , , () . , โ€” ! (never). , .



eh_personality



eh_personality โ€” " ", , . , Copy โ€” , , . , #[lang = "copy"], .



, , , , ! , .



eh_personality , "" . Rust , . , , (libunwind Linux Windows), .





Rust . , . , . โ€” Cargo.toml:



[profile.dev]
panic = "abort"

[profile.release]
panic = "abort"


abort dev ( cargo build), release (cargo build --release). eh_personality.



. :



> cargo build
error: requires `start` lang_item


start



, main . . , (Java, C#, JavaScript...) (, Go). main .



Rust , crt0, . , , . Rust , start, Rust , main().



, crt0, . crt0.





, , #![no_main].



#![no_std]
#![no_main]

use core::panic::PanicInfo;

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


main(), . _start:



#[no_magnle]
pub extern "C" fn _start() -> ! {
  loop {}
}


#[no_mangle], , _start, , , _ZN3blog_os4_start7hb173fedf945531caE. , .



extern "C", , , Rust ( , , , ). , .



, , , !, , . , , , ( ).



, cargo build, .





โ€” , , , . , , .



, , , . 2 : , .



""



Rust . Windows x86-64, Rust .exe x86-64. .



Rust ( ) target triples. , rustc --version --verbose:



rustc 1.47.0-nightly (576d27c5a 2020-08-12)
binary: rustc
commit-hash: 576d27c5a6c80cd39ef57d7398831d8e177573cc
commit-date: 2020-08-12
host: x86_64-unknown-linux-gnu
release: 1.47.0-nightly
LLVM version: 10.0


(Linux x86-64). , โ€” host. , :



  • x86-64,
  • : Linux,
  • ABI: GNU


, Rust , - ( , Linux) (libc, libunwind ). , .



thumbv7em-none-eabihf, ARM. , , (none). , Rustup:



rustup target add thumbv7em-none-eabihf


:



cargo build --target thumbv7em-none-eabihf


--target, - . , , .



, . thumbv7em-none-eabihf x86-64. ( ), . , m1rko, ( ).





, :



src/main.rs:



#![no_std] // don't link the Rust standard library
#![no_main] // disable all Rust-level entry points

use core::panic::PanicInfo;

#[no_mangle] // don't mangle the name of this function
pub extern "C" fn _start() -> ! {
  // this function is the entry point, since the linker looks for a function
  // named `_start` by default
  loop {}
}

/// This function is called on panic.
#[panic_handler]
fn panic(_info: &PanicInfo) -> ! {
  loop {}
}


Cargo.toml:



[package]
name = "crate_name"
version = "0.1.0"
authors = ["Author Name <author@example.com>"]

# the profile used for `cargo build`
[profile.dev]
panic = "abort" # disable stack unwinding on panic

# the profile used for `cargo build --release`
[profile.release]
panic = "abort" # disable stack unwinding on panic


โ€” :



cargo build --target thumbv7em-none-eabihf


. . , , . -, .




All Articles