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
1.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
920
Kernel/VM #14 発表資料
orumin
1
570
Unikernels report
orumin
2
450
第12回カーネル/VM探検隊
orumin
0
360
第11回 Kernel/VM探検隊 発表資料
orumin
1
560
KernelVM night! LT
orumin
0
450
Other Decks in Programming
See All in Programming
What Spring Developers Should Know About Jakarta EE
ivargrimstad
0
440
ソフトウェア品質を数字で捉える技術。事業成長を支えるシステム品質の マネジメント
takuya542
1
12k
「Cursor/Devin全社導入の理想と現実」のその後
saitoryc
0
800
XP, Testing and ninja testing
m_seki
3
240
PHPでWebSocketサーバーを実装しよう2025
kubotak
0
280
来たるべき 8.0 に備えて React 19 新機能と React Router 固有機能の取捨選択とすり合わせを考える
oukayuka
2
920
RailsGirls IZUMO スポンサーLT
16bitidol
0
180
Claude Code + Container Use と Cursor で作る ローカル並列開発環境のススメ / ccc local dev
kaelaela
6
3.4k
AI駆動のマルチエージェントによる業務フロー自動化の設計と実践
h_okkah
0
100
初学者でも今すぐできる、Claude Codeの生産性を10倍上げるTips
s4yuba
16
11k
プロダクト志向なエンジニアがもう一歩先の価値を目指すために意識したこと
nealle
0
130
iOS 26にアップデートすると実機でのHot Reloadができない?
umigishiaoi
0
130
Featured
See All Featured
I Don’t Have Time: Getting Over the Fear to Launch Your Podcast
jcasabona
32
2.4k
Responsive Adventures: Dirty Tricks From The Dark Corners of Front-End
smashingmag
251
21k
No one is an island. Learnings from fostering a developers community.
thoeni
21
3.4k
Fashionably flexible responsive web design (full day workshop)
malarkey
407
66k
RailsConf 2023
tenderlove
30
1.1k
jQuery: Nuts, Bolts and Bling
dougneiner
63
7.8k
Put a Button on it: Removing Barriers to Going Fast.
kastner
60
3.9k
Scaling GitHub
holman
459
140k
Build your cross-platform service in a week with App Engine
jlugia
231
18k
How GitHub (no longer) Works
holman
314
140k
Why You Should Never Use an ORM
jnunemaker
PRO
58
9.4k
How to train your dragon (web standard)
notwaldorf
94
6.1k
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