تهيئة البيئة. ثنائي عارية ، أو قابل للتنفيذ بدون رئيسي ()
تتمثل الخطوة الأولى في كتابة نظام التشغيل الخاص بك في إنشاء ثنائي لا يعتمد على المكتبات القياسية ، وهذا يجعل من الممكن تشغيل التعليمات البرمجية بدون نظام تشغيل - نحن نكتب نظامنا الخاص بنا.
يتم تطوير المدونة الأصلية على GitHub . اترك تعليقاتك للأصل في صفحة القضايا بالمستودع أعلاه ، وللترجمة - في PM أو التعليقات أو هنا . الكود المكتوب في هذه المقالة وارد في post-01.
المقدمة
من أجل كتابة نظام التشغيل الخاص بنا ، نحتاج إلى رمز لا يعتمد على مكتبات أو وظائف نظام تشغيل آخر. هذا يعني أنه لا يمكننا استخدام الخيوط والملفات وذاكرة الكومة والشبكات والإخراج الطرفي وما إلى ذلك. ولكن يمكن التغلب على هذا عن طريق كتابة نظام التشغيل والسائقين الخاصين بك.
ونحن لا يمكن استخدام أكثر من المكتبة القياسية الصدأ ، ولكن هناك أيضا العديد من الوظائف أننا يمكن استخدامها. على سبيل المثال المكررات ، إغلاق ، مطابقة النقش ، الخيار و النتيجة ، سلسلة في التنسيق ، وبالطبع مفهوم الملكية . سيسمح لك ذلك بكتابة النواة الخاصة بك بأسلوب عالي المستوى دون القلق بشأن السلوك غير المحدد أو أمان الذاكرة .
تشرح هذه المقالة كيفية إنشاء ملف مستقل قابل للتنفيذ ولماذا تحتاج إليه. إذا كنت تريد مثالاً فقط ، فيمكنك التمرير إلى قسم الاستنتاج.
تعطيل المكتبة القياسية
بشكل افتراضي ، يتم إنشاء التعليمات البرمجية المجمعة باستخدام المكتبة القياسية ، والتي يحتاجها نظام التشغيل لتنفيذ وظائف مثل الملفات والشبكات وما إلى ذلك. يعتمد أيضًا على مكتبة C: القياسية 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), .
[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
. . , , . -, .