Mise en place de l'environnement. Binaire nu ou exécutable sans main ()
La première étape dans l'écriture de votre propre OS est de créer un binaire qui ne dépend pas des bibliothèques standard, cela permet d'exécuter du code sans OS - nous écrivons le nôtre.
Le blog original est en cours de développement sur GitHub . Laissez vos commentaires à l'original sur la page Problèmes du référentiel ci-dessus, et à la traduction - en PM, commentaires ou ici . Le code écrit dans cet article est contenu dans post-01
.
introduction
Pour écrire notre propre système d'exploitation, nous avons besoin d'un code qui ne dépend pas des bibliothèques ou des fonctions d'un autre système d'exploitation. Cela signifie que nous ne pouvons pas utiliser de threads, de fichiers, de mémoire de tas, de mise en réseau, de sortie de terminal, etc. Mais cela peut être surmonté en écrivant votre propre système d'exploitation et vos propres pilotes.
Nous ne pouvons pas utiliser la plupart de la bibliothèque standard Rust , mais il existe également de nombreuses fonctions que nous pouvons utiliser. Par exemple, les itérateurs , les fermetures , les correspondances de modèles , les options et les résultats , le formatage des chaînes et bien sûr le concept de propriété . Cela vous permettra d'écrire votre noyau dans un style de haut niveau sans vous soucier du comportement indéfini ou de la sécurité de la mémoire .
Cet article explique comment créer un fichier exécutable autonome et pourquoi vous en avez besoin. Si vous avez juste besoin d'un exemple, vous pouvez faire défiler jusqu'à la section Conclusion.
Désactivation de la bibliothèque standard
, , , .. : 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
. . , , . -, .