Binary Translation型エミュレータを作っている。ゲストマシンはRISC-Vで、ホストマシンはx86である。基本的な命令が動き出したので、以前に作ったELFファイルローダを使ってBinary Translation型エミュレータにELFファイルをロードする機能を実装して行きたい。
ELFファイルのロードは、ELFLoader::new(filename)
でELFファイルをオープンする。
let loader = match ELFLoader::new(filename) { Ok(loader) => loader, Err(error) => panic!("There was a problem opening the file: {:?}", error), };
必要な情報は、
- ELFヘッダのロード
- セクションヘーダのロード
- セクションヘッダから必要なセクションを選択してロード
という順番を取る。まずはELFヘッダのロードである。ELFヘッダはセクションの先頭などの情報を引き出すために必要なので、必須情報だ。
let elf_header = loader.get_elf_header(); elf_header.dump();
セクションヘッダのロードは、すべてのセクションをロードする。sh_headers
にはすべてのセクションの開始位置とサイズが格納されているので、これをベクタに格納する。
let mut sh_headers = Vec::new(); for sh_idx in 0..elf_header.e_shnum { let shdr: SectionHeader = loader.get_section_header( &elf_header, elf_header.e_shoff, elf_header.e_shentsize, sh_idx.into(), ); sh_headers.push(shdr); }
最後に、このセクションヘッダの情報に基づきデータをロードしていく。格納先はriscv_guestcode
で、ベクトル型の配列に格納していく。
let mut riscv_guestcode: Vec<u8> = Vec::new(); // Dump All Section Headers for sh_header in sh_headers { if sh_header.sh_flags != 0 { sh_header.dump(); loader.load_section(&mut riscv_guestcode, sh_header.sh_offset, sh_header.sh_size); } }
各セクションのsh_flags
が設定されているセクションについてロードしていく。とりあえず今はアドレスについては考慮していない。
例えば、以下のRISC-Vコードをコンパイルしてロードしてみよう。
simple_start.S
_start: addi x1, x0, 11 addi x2, x0, 22 addi x3, x0, 33 addi x4, x0, 44 addi x4, x0, 45 addi x5, x0, 55 addi x6, x0, 66 addi x7, x0, 77 addi x8, x0, 88 addi x9, x0, 99 addi x10, x0, 100 addi x11, x0, 111 addi x12, x0, 122 addi x13, x0, 133 addi x14, x0, 144 addi x14, x0, 145 addi x15, x0, 155 addi x16, x0, 166 addi x17, x0, 177 addi x18, x0, 188 addi x19, x0, 199 addi x20, x0, 210 ret
$ riscv64-unknown-elf-as simple_start.S -o simple_start.o $ riscv64-unknown-elf-ld simple_start.o -o simple_start $ riscv64-unknown-elf-objdump -d simple_start > simple_start.dmp
これをロードして実行してみる。
$ cargo run simple_start
E_TYPE = ET_EXEC E_MACHINE = RISCV E_VERSION = 1 E_ENTRY = 0x10078 E_PHOFF = 0x40 E_SHOFF = 0x1f8 E_FLAGS = 4 E_EHSIZE = 64 E_PHENTSIZE = 56 E_PHNUM = 1 E_SHENTSIZE = 64 E_SHNUM = 5 E_SHSTRNDX = 4 == Section Dump == Name : 1b Type : 0x1 Flags : 0x6 Addr : 0x10078 Offset : 0x78 Size : 0x5c Link : 0x0 Info : 0x0 AddrAlign : 0x4 EntSize : 0x0 inst = 00b00093 inst = 01600113 inst = 02100193 inst = 02c00213 inst = 02d00213 inst = 03700293 inst = 04200313 inst = 04d00393 inst = 05800413 inst = 06300493 inst = 06400513 inst = 06f00593 inst = 07a00613 inst = 08500693 inst = 09000713 inst = 09100713 inst = 09b00793 inst = 0a600813 inst = 0b100893 inst = 0bc00913 inst = 0c700993 inst = 0d200a13 inst = 00008067
上手くロードできている。実行結果も良好だ。
x00 = 0000000000000000 x01 = 000000000000000b x02 = 0000000000000016 x03 = 0000000000000021 x04 = 000000000000002d x05 = 0000000000000037 x06 = 0000000000000042 x07 = 000000000000004d x08 = 0000000000000058 x09 = 0000000000000063 x10 = 0000000000000064 x11 = 000000000000006f x12 = 000000000000007a x13 = 0000000000000085 x14 = 0000000000000091 x15 = 000000000000009b x16 = 00000000000000a6 x17 = 00000000000000b1 x18 = 00000000000000bc x19 = 00000000000000c7 x20 = 00000000000000d2 x21 = 0000000000000000 x22 = 0000000000000000 x23 = 0000000000000000 x24 = 0000000000000000 x25 = 0000000000000000 x26 = 0000000000000000 x27 = 0000000000000000 x28 = 0000000000000000 x29 = 0000000000000000 x30 = 0000000000000000 x31 = 0000000000000000