FPGA開発日記

カテゴリ別記事インデックス https://msyksphinz.github.io/github_pages , English Version https://fpgadevdiary.hatenadiary.com/

Binary Translation型エミュレータを作る(ELFローダの組み込み)

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
f:id:msyksphinz:20200822224858p:plain