Closed tomoyuki-nakabayashi closed 6 years ago
先にC言語でやるのも良いかもしれない?
https://os.phil-opp.com/set-up-rust/
ここを参考にベアメタルバイナリを作る。
rustup override add nightly
うんうん、できている。
build/hello-x86_64.bin: file format elf64-x86-64
Disassembly of section .text:
0000000000000000 <start>:
0: b8 00 00 00 00 mov $0x0,%eax
5: e9 06 00 00 00 jmpq 10 <rust_main>
a: f4 hlt
b: 90 nop
Disassembly of section .text.rust_main:
0000000000000010 <rust_main>:
10: eb 00 jmp 12 <rust_main+0x2>
12: eb fe jmp 12 <rust_main+0x2>
#![feature(panic_implementation)]
#![no_std]
#[no_mangle]
pub extern fn rust_main() {
loop{}
}
use core::panic::PanicInfo;
#[panic_implementation]
#[no_mangle]
pub fn panic(_info: &PanicInfo) -> ! {
loop {}
}
12: eb fe jmp 12 <rust_main+0x2>
よく見たら、アドレス-2しているな。今unsignedしか対応していない気がする。直さないと。
Rust関数を空にすると、↓のようになる。
0000000000000010 <rust_main>:
10: c3 retq
帰って来ようとするとretが必要か。まぁそりゃそうか。
にしても、ずいぶんもったいない使い方しているな。オブジェクトファイルが異なるから仕方ないのか?
5: e9 06 00 00 00 jmpq 10 <rust_main>
とりあえずjmpqを実装すればRustが呼べる。
#[no_mangle]
pub extern fn rust_main() {
unsafe {
asm!("mov rax, 0x10000000" :::: "intel");
}
}
10: 48 c7 c0 00 00 00 10 mov $0x10000000,%rax
nasmでやるとターゲットをraxにしても、eax相当の命令が発行されているな。 Movも作り直さないとダメか。
ndisasm -b 64 filename
でdisassembleできる。
mov, jmpq, hltを実装すると、とりあえずRustを動かせる。 欲を言うと、callとretも欲しい。
nasmのバイナリ出力が変(というか最適化されてしまう)なので、llvm-asの利用を考える。
これでintelのシンタックスが使える。
-x86-asm-syntax - Choose style of code to emit from X86 backend:
=att - Emit AT&T-style assembly
=intel - Emit Intel-style assembly
と思ったが、llvmの中間表現が入力なのかー。うーむ。
https://stackoverflow.com/questions/48596247/why-nasm-on-linux-changes-registers-in-x86-64-assembly
なるほど。strict
を付けると最適化を防げると。
確かに、最適化されていない。これで行こう。
$ cat simple_add.asm
bits 64
mov rax, strict 1
mov rcx, 2
mov rdx, 0
mov rbx, 0
inc rcx
add rax, rcx
hlt
$ nasm simple_add.asm
$ ndisasm -b 64 simple_add
00000000 48B8010000000000 mov rax,0x1
-0000
0000000A B902000000 mov ecx,0x2
0000000F BA00000000 mov edx,0x0
00000014 BB00000000 mov ebx,0x0
00000019 48FFC1 inc rcx
0000001C 4801C8 add rax,rcx
0000001F F4 hlt
とりあえず、modrmを使うmovと、jmpqを作ってRustの関数を動かそう。
最終的に、ModRmを使うmovとcall/retを実装した。
https://github.com/tomoyuki-nakabayashi/baremetal_hello_in_rust
のRustインラインアセンブラからHelloが出力された!やったぜ!
スタートアップルーチンを自分で書いてRustの関数を呼び出す。