设置环境。裸二进制文件,或不带main()的可执行文件
编写自己的操作系统的第一步是创建一个不依赖于标准库的二进制文件,这使得在没有操作系统的情况下运行代码成为可能-我们正在编写自己的操作系统。
原始博客正在GitHub上开发。将您的评论保留在上面存储库的“问题”页面上的原始文档中,以及翻译成PM的注释或此处。本文中编写的代码包含在中 post-01
。
介绍
为了编写我们自己的OS,我们需要不依赖于另一个操作系统的库或功能的代码。这意味着我们不能使用线程,文件,堆内存,网络,终端输出等。但这可以通过编写自己的OS和驱动程序来克服。
我们不能使用大多数Rust标准库,但是也可以使用许多功能。例如,迭代器,闭包,模式匹配,选项和结果,字符串格式,当然还有所有权概念。这将使您能够以高级样式编写内核,而不必担心未定义的行为或内存安全性。
本文介绍了如何创建独立的可执行文件以及为什么需要它。如果只需要一个示例,则可以滚动到结论部分。
禁用标准库
默认情况下,编译后的代码是使用标准库构建的,操作系统需要该库来实现文件,网络等功能。它还取决于C:标准库libc
,该库更多地使用了OS功能。而且由于我们正在编写一个替换常规OS的程序,因此这不适合我们。您需要使用禁用库no_std
。
首先,让我们使用Cargo创建一个项目。这是使用命令行完成的:
cargo new os-in-rust --bin --edition 2018
我为该项目命名os-in-rust
(以避免与原始博客混淆),但是您可以选择任何名称。该标志--bin
表明您需要一个将被编译成可执行文件而不是库的项目。--edition 2018
意味着您需要使用Rust 2018版。货物将生成这样的文件夹结构:
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
. . , , . -, .