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
560
Unikernels report
orumin
2
450
第12回カーネル/VM探検隊
orumin
0
360
第11回 Kernel/VM探検隊 発表資料
orumin
1
550
KernelVM night! LT
orumin
0
450
Other Decks in Programming
See All in Programming
當開發遇上包裝:AI 如何讓產品從想法變成商品
clonn
0
2.5k
漸進。
ssssota
0
960
Devinで実践する!AIエージェントと協働する開発組織の作り方
masahiro_nishimi
6
2.5k
JVM の仕組みを理解して PHP で実装してみよう
m3m0r7
PRO
1
240
Use Perl as Better Shell Script
karupanerura
0
640
ワイがおすすめする新潟の食 / 20250530phpconf-niigata-eve
kasacchiful
0
180
OpenNext + Hono on Cloudflare でイマドキWeb開発スタックを実現する
rokuosan
0
110
iOSアプリ開発もLLMで自動運転する
hiragram
6
2.1k
Proxmoxをまとめて管理できるコンソール作ってみました
karugamo
1
390
eBPFを用いたAIネットワーク監視システム論文の実装 / eBPF Japan Meetup #4
yuukit
3
600
List Unfolding - 'unfold' as the Computational Dual of 'fold', and how 'unfold' relates to 'iterate'"
philipschwarz
PRO
0
120
「MCPを使ってる人」が より詳しくなるための解説
yamaguchidesu
0
570
Featured
See All Featured
Unsuck your backbone
ammeep
671
58k
ReactJS: Keep Simple. Everything can be a component!
pedronauck
667
120k
Designing for humans not robots
tammielis
253
25k
Six Lessons from altMBA
skipperchong
28
3.8k
"I'm Feeling Lucky" - Building Great Search Experiences for Today's Users (#IAC19)
danielanewman
228
22k
Sharpening the Axe: The Primacy of Toolmaking
bcantrill
42
2.3k
Build The Right Thing And Hit Your Dates
maggiecrowley
35
2.7k
Become a Pro
speakerdeck
PRO
28
5.4k
Rebuilding a faster, lazier Slack
samanthasiow
81
9k
[Rails World 2023 - Day 1 Closing Keynote] - The Magic of Rails
eileencodes
34
2.3k
It's Worth the Effort
3n
184
28k
The Power of CSS Pseudo Elements
geoffreycrofte
76
5.8k
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