Binary Translation方式の命令セットエミュレータのRust実装、ある程度進んできたが、どんどん複雑なテストパタンを確認していかなければならない。デバッグ機能についてだが、ホスト命令(つまりx86命令)のディスアセンブル機能を実装したい。つまり、変換後の命令に対してディスアセンブラを適用し、どのような命令に変換されたのかを確認する機能だ。
これには、iced-x86
というクレートを活用することにした。
https://crates.io/crates/iced-x86
使い方については、ほとんどREADMEに追従するような形で使用した。まあ変換後の命令を渡してそのままstdoutに出力してほしいだけなので簡単だ。
TCGX86::tcg_gen(&self, pc_address, tcg, &mut mc_byte); for be in &mc_byte { let be_data = *be; self.m_tcg_tb_vec.push(be_data); } // disassemble_x86を呼び出す。 disassemble_x86(mc_byte.as_slice(), self.m_tb_text_mem.data()); pc_address += mc_byte.len() as u64; } ...
pub fn disassemble_x86(bytes: &[u8], host_code_addr: *const u8) { let mut decoder = Decoder::new(EXAMPLE_CODE_BITNESS, bytes, DecoderOptions::NONE); decoder.set_ip(unsafe { host_code_addr.offset(0) as u64 }); // Formatters: Masm*, Nasm*, Gas* (AT&T) and Intel* (XED) let mut formatter = GasFormatter::new(); // Change some options, there are many more formatter.options_mut().set_digit_separator("_"); formatter.options_mut().set_first_operand_char_index(10); // String implements FormatterOutput let mut output = String::new(); // Initialize this outside the loop because decode_out() writes to every field let mut instruction = Instruction::default(); // The decoder also implements Iterator/IntoIterator so you could use a for loop: // for instruction in &mut decoder { /* ... */ } // or collect(): // let instructions: Vec<_> = decoder.into_iter().collect(); // but can_decode()/decode_out() is a little faster: while decoder.can_decode() { // There's also a decode() method that returns an instruction but that also ...
デバッグモード二次出力するようにオプションを整える。実行してみよう。
$ cargo run -- --debug --elf-file /home/msyksphinz/work/riscv/riscv-tools/riscv-tests/build/isa/rv64ui-p-simple
Guest PC Address = 0000004c f1402573 : 00051063 :
00007F7BA53E0000 48BF201316C8FF7F0000 movabs $0x7FFF_C816_1320,%rdi 00007F7BA53E000A 48BE0A00000000000000 movabs $0xA,%rsi 00007F7BA53E0014 48BA0000000000000000 movabs $0,%rdx 00007F7BA53E001E 48B9140F000000000000 movabs $0xF14,%rcx 00007F7BA53E0028 FF9518030000 callq *0x318(%rbp) Added offset. code_ptr = 3e 00007F7BA53E0000 488B8558000000 mov 0x58(%rbp),%rax 00007F7BA53E0007 483B8508000000 cmp 8(%rbp),%rax 00007F7BA53E000E 0F850A000000 jne 0x0000_7F7B_A53E_001E[f:id:msyksphinz:20200930225446p:plain] 00007F7BA53E0000 48B85400000000000000 movabs $0x54,%rax 00007F7BA53E000A 48898508020000 mov %rax,0x208(%rbp) 00007F7BA53E0011 E9B7FF0200 jmp 0x0000_7F7B_A540_FFCD Offset is set 58 00007F7BA53E0000 48B85000000000000000 movabs $0x50,%rax 00007F7BA53E000A 48898508020000 mov %rax,0x208(%rbp) 00007F7BA53E0011 E9A1FF0200 jmp 0x0000_7F7B_A540_FFB7
上手く行ったようだ。f1402573
と 00051063
のRISC-Vの2命令 (本当はcsrr a0, mhartid
とbnez a0, pc + 0
命令)がどのようなx86命令に変換されているかを確認することができるようになった。