Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
第13回Kernel/VM勉強会発表資料
Search
orumin
July 22, 2017
Programming
1
1.6k
第13回Kernel/VM勉強会発表資料
2017/07/22 に行なわれた Kernel/VM 勉強会の発表資料です。
orumin
July 22, 2017
Tweet
Share
More Decks by orumin
See All by orumin
ヴィンテージマシンと付き合う - kernel/vm online 5
orumin
0
1k
むかしの RISC、むかしの Unix
orumin
7
3.5k
Fundamental of architecture to implementing OS on AArch64
orumin
3
4.8k
Kernel/VM Kansai #9
orumin
0
910
Kernel/VM #14 発表資料
orumin
1
550
Unikernels report
orumin
2
440
第12回カーネル/VM探検隊
orumin
0
350
第11回 Kernel/VM探検隊 発表資料
orumin
1
540
KernelVM night! LT
orumin
0
440
Other Decks in Programming
See All in Programming
AIコーディングエージェントを 「使いこなす」ための実践知と現在地 in ログラス / How to Use AI Coding Agent in Loglass
rkaga
3
420
地域ITコミュニティの活性化とAWSに移行してみた話
yuukis
0
240
State of Namespace
tagomoris
4
1.8k
Module Boundaries and Architecture with Forensic Analysis @NxSummit Amsterdam 2025
manfredsteyer
PRO
0
100
RuboCop: Modularity and AST Insights
koic
2
1.3k
AIコーディングワークフローの試行 〜AIエージェント×ワークフローでの自動化を目指して〜
rkaga
3
3.7k
Ruby's Line Breaks
yui_knk
2
1.2k
The Implementations of Advanced LR Parser Algorithm
junk0612
1
320
Rollupのビルド時間高速化によるプレビュー表示速度改善とバンドラとASTを駆使したプロダクト開発の難しさ
plaidtech
PRO
1
180
Deoptimization: How YJIT Speeds Up Ruby by Slowing Down / RubyKaigi 2025
k0kubun
0
850
小田原でみんなで一句詠みたいな #phpcon_odawara
stefafafan
0
340
PHP で学ぶ OAuth 入門
azuki
1
200
Featured
See All Featured
Agile that works and the tools we love
rasmusluckow
328
21k
I Don’t Have Time: Getting Over the Fear to Launch Your Podcast
jcasabona
32
2.2k
"I'm Feeling Lucky" - Building Great Search Experiences for Today's Users (#IAC19)
danielanewman
227
22k
Save Time (by Creating Custom Rails Generators)
garrettdimon
PRO
31
1.1k
Performance Is Good for Brains [We Love Speed 2024]
tammyeverts
9
760
Music & Morning Musume
bryan
47
6.5k
Gamification - CAS2011
davidbonilla
81
5.2k
The Success of Rails: Ensuring Growth for the Next 100 Years
eileencodes
45
7.2k
How STYLIGHT went responsive
nonsquared
99
5.5k
Done Done
chrislema
183
16k
The Straight Up "How To Draw Better" Workshop
denniskardys
232
140k
Git: the NoSQL Database
bkeepers
PRO
430
65k
Transcript
C 以外でのベアメタルプログラミング XXX Jul 22th, 2017 1 / 27
自己(事故)紹介 orumin Twitter ID: @kotatsu_mi 最近自宅のサーバの電源と PT3 が雷に撃たれました。 雷サージ対策は忘れずにやろうね! アンテナ線にも電話線にもサージプロテクタは存在する
2 / 27
緒言 ベアメタルプログラミング いわゆる freestanding 環境 libc 他が存在しない みなさんよくやってますよね? よくつかわれるのは C
や C++ どうして C をつかうのか 3 / 27
ベアメタルプログラミングと C メリット 生ポインタで特定のアドレスへの I/O 操作といったことが簡単にでき る,また,この分野で枯れており,ノウハウも豊富 デメリット 型システムが貧弱,最近のクールな言語機能が使えない 4
/ 27
C 以外でベアメタルプログラミング 複数の代替手段 D 言語,C♯,Rust … (いますぐ採用するとかなくても)今後のために C 以外でやるノウハウも得てお かないとそのうち死ぬので
Rust 既にかなりの規模のそれなりにちゃんと動く OS が作られている(Redox)実績 C♯ も 2011 年ぐらいから Cosmos という OS があったりする C♯ でのベアメタルプログラミングも調べて話そうとすると話者の力量不足でどっち つかずの内容になるので割愛しました そのうちやるかも? 5 / 27
Rust OCaml と C++ の血を感じる言語 ML 系の強力な型システム 所有権など,独特だが C++ を既に知ってる人間がわりと違和感なく使える強力な
機能 nightly コンパイラで freestanding をサポート stable 入りはまだですかー! 様々な機能や設計が C++ のカウンターっぽい c.f.) 過去の KernelVM での @omasanori さんの発表 https://speakerdeck.com/omasanori/rustru-men-yi-qian-fa-biao-ban 6 / 27
Rust(nightly)のインストールとテスト $ curl https://sh.rustup.rs -sSf | sh -s -- --default-toolchain=nightly
-y $ . ~/.cargo/env $ cargo new --bin hello-rust 7 / 27
Rust のテスト 右のようなディレクトリツリーが出来あがる 作成されるファイルは下例 実行は cargo run cargo は gem
みたいなもの。ビルドツールか つパッケージマネージャ。 Rust のパッケージは https://crates.io に ある hello-rust Cargo.toml src/ main.rs [package] name = ”hello-rust” version = ”0.1.0” authors = [”orumin <
[email protected]
>”] [dependencies] fn main() { println!(”Hello, world!”); } 8 / 27
Rust でベアメタルをするにはどうすれば良いか UEFI apps を例に step-by-step で紹介します! Linux の人は手元で試してみてください TL;DR
https://github.com/orumin/rust-uefi-sample.git を clone して make run rust-uefi-sample/ Makefile Cargo.toml x86_64-unknown-efi.json src/ lib.rs 9 / 27
Cargo.toml [package] name = ”uefi-sample” version = ”0.1.0” authors =
[”orumin <
[email protected]
>”] [dependencies] uefi = { git = ”https://github.com/orumin/rust-uefi” } rlibc = ”1.0” [lib] crate-type = [”staticlib”] [profile.dev] panic = ”abort” [profile.release] panic = ”abort” 10 / 27
Cargo.toml パッケージ名や依存パッケージを記述 [lib] セクションをつくり,src/lib.rs を記述するとライブラリとして作られる 今回はオブジェクトファイルだけ作成して手動でリンクしたかった 依存パッケージは名前だけ書いておくと crates.io からもってくる path
= に続けてパスを記述すると他のディレクトリのプロジェクトを依存に指定 git = に続けて Git repo を記述すると自動で clone とビルドしてくれます 11 / 27
target json Cargo は json で custom ターゲットを作れる { ”arch”:
”x86_64”, ”os”: ”efi”, ”llvm-target”: ”x86_64-efi-none-gnu”, ”target-endian”: ”little”, ”target-pointer-width”: ”64”, ”function-sections”: false, ”no-compiler-rt”: true, ”data-layout”: ”e-m:e-i64:64-f80:128-n8:16:32:64-S128”, ”linker”: ”x86_64-efi-pe”, ”linker-flavor”: ”ld”, ”pre-link-args”: [ ”subsystem”, ”10” ] } 12 / 27
target json 今回は UEFI 向けに PE バイナリを作りたいので target の json
を記述 arm-none-eabi などでも記述 ただの x86_64 の ELF なら要らないかも? 13 / 27
ソースコード #![no_std] #![feature(asm)] #![feature(intrinsics)] #![feature(lang_items)] extern crate uefi; extern crate
rlibc; use core::mem; #[allow(unreachable_code)] #[no_mangle] pub extern ”win64” fn efi_main(hdl: uefi::Handle, sys: uefi::SystemTable) -> uefi::Status { uefi::initialize_lib(&hdl, &sys); let bs = uefi::get_system_table().boot_services(); let rs = uefi::get_system_table().runtime_services(); 14 / 27
ソースコード uefi::get_system_table().console().write(”Hello, World!\n\rvendor: ”); uefi::get_system_table().console().write_raw(uefi::get_system_table().vendor()); uefi::get_system_table().console().write(”\n\r”); loop { } uefi::Status::Success
} #[no_mangle] pub fn abort() -> ! { loop {} } #[no_mangle] pub fn breakpoint() -> ! { loop {} } #[no_mangle] pub extern ”C” fn _Unwind_Resume() -> ! { loop {} } #[lang = ”eh_personality”] #[no_mangle] pub extern fn rust_eh_personality() {} 15 / 27
ソースコード #[lang = ”panic_fmt”] #[no_mangle] pub extern fn rust_begin_panic(_msg: core::fmt::Arguments,
_file: &’static str, _line: u32) -> ! { loop {} } 16 / 27
ソースコード解説 #![no_std] 標準ライブラリをリンクしなくなる 標準ライブラリのうち,アーキテクチャ非依存な便利機能は core ライブラリを use すれば使えるものもある 17 /
27
no_std でフォーマット出力 e.g.) use core::fmt::Write; impl Write for Writer {
fn write_str(&mut self, s: &str) -> core::fmt::Result { 引数でうけた文字列 s について出力を自分で実装; Ok(()) // 失敗なら Err(foo) でエラーの値返す } } これだけで,write!() マクロの実装が得られる let mut w = Writer {}; write!(w, ”foo {}”, bar).unwrap(); 18 / 27
#![feature(lang_items)] eh_personality とか panic_fmt とか eh_personality GCC の personality 関数の代わりのシンボル
LLVM で言語の例外ハンドリングに使う unwind panic_fmt Rust で panic!() を使うときのシンボル デバッグ文字列出力とか作っておくと良い 19 / 27
extern extern “C” などとすると C 互換の ABI になる #[no_mangle] 付けると名前マングルをしない
既存のライブラリを置き換える何かを作るのにもべんりかも UEFI は x86_64 だと Microsoft’s 64-bit call convention を使う extern “win64” で対応 20 / 27
ではビルドをしてみましょう $ cargo install xargo $ xargo build --target x86_64-unknown-efi
Xargo を導入 cargo build の際に core ライブラリなどをターゲットのアーキでビルドしてく れる 素の cargo だとヘンなアーキテクチャ使うのに core をそこに合わせてビルドしな いといけない 21 / 27
binutils とリンク 今回は UEFI ターゲットの PE バイナリを作りたいので普通の binutils だとダメ $
curl -O https://orum.in/distfiles/x86_64-efi-pe-binutils.tar.xz $ mkdir -p $PWD/toolchain $ tar xf x86_64-efi-pe-binutils.tar.xz -C $PWD/toolchain $ export PATH=$PATH:$PWD/toolchain/usr/bin/ $ pushd $ cd target/x86_64-unknown-efi/debug $ ar x *.a $ popd $ x86_64-efi-pe-ld --gc-sections --oformat pei-x86-64 \ --subsystem 10 -pie -e efi_main \ -o bootx64.efi \ target/x86_64-unknown-efi/debug/*.o 22 / 27
実行 $ dd if=/dev/zero of=fat.img bs=1k count=1440 $ mformat -i
fat.img -f 1440 :: $ mmd -i fat.img ::/EFI $ mmd -i fat.img ::/EFI/BOOT $ mcopy -i fat.img bootx64.efi ::/EFI/BOOT $ curl -O https://orum.in/distfiles/ovmf.fd $ qemu-system-x86_64 -enable-kvm -net none -m 1024 \ -bios ovmf.fd -usb -usbdevice disk::fat.img 23 / 27
これだと見えづらいので…… https: //github.com/orumin/rust-uefi-sample/blob/master/src/lib.rs Graphic Output Protocol の取得,設定 BLT 24 /
27
conclusion Rust 便利 C 以外でもベアメタルしたい! 25 / 27
こぼれ話1 質問:@nullpo_head さん「自作 OS 勉強会だと Box が使えなくて辛いとかあっ たけどどうやってるの? 」 回答:
「まだそこらへんがっつりやるステージに入れてないが,そもそも Box と かは自前実装する方法があるので問題がないと思う。 」 https://rust-lang-ja.github.io/the-rust-programming-language-ja/ 1.6/book/custom-allocators.html 実は上記の通り公式ドキュメントがある ベアメタル以外でも使えるのでゲームエンジンとかやる人にも良いのではないか 26 / 27
こぼれ話2 Rust のコンパイラ機能 #[start] 特定のシンボルの前(たとえば pub fn app_main() とかの前の行)に付けておく と,エントリポイントにしてくれる
#[link_section = “.test_section”] この行のところが ELF の.test_section になる。便利。 27 / 27