FPGA開発日記

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

Rustで作ったRISC-VシミュレータにELFロード機能を追加する

Rustを使ってELFファイルをダンプするプログラムが動くようになったので、今度はこれをRISC-VシミュレータにインポートしてELFファイルを読み込むことができるようにする。

まずはELF Loaderをインポートして、ELFファイルを読み込んだら、すべてのセクションについてデータをダンプして適切なメモリ領域に値を書き込む。

    let loader = match ElfLoader::new(filename) {
        Ok(loader) => loader,
        Err(error) => {
            panic!("There was a problem opening the file: {:?}", error)
        },
    };

...
    // Dump All Section Headers
    for sh_header in sh_headers {
        sh_header.dump();

        let mut sh_addr = sh_header.sh_addr;
        for byte_addr in (sh_header.sh_offset..(sh_header.sh_offset + sh_header.sh_size)) {
            let byte_data = loader.get_byte(byte_addr as usize);
            riscv_core.write_memory_byte(sh_addr as Addr64T, byte_data as Xlen64T);
            sh_addr += 1;
        }

しかしこれではメモリにロードすべきセクション以外のものまでロードしてしまうので、必要なセクションのみロードしたい。このために、セクションヘッダのtypeフィールドを使って、フィールドがPROGBITSのセクションのみロードするようにしよう。

/* Legal values for sh_type (section type).  */

#define SHT_NULL      0     /* Section header table entry unused */
#define SHT_PROGBITS      1     /* Program data */
#define SHT_SYMTAB    2     /* Symbol table */
#define SHT_STRTAB    3     /* String table */
#define SHT_RELA      4     /* Relocation entries with addends */
#define SHT_HASH      5     /* Symbol hash table */
#define SHT_DYNAMIC   6     /* Dynamic linking information */
...

PROGBITSの値は1なので、とりあえず以下のように条件判定を付ける。

    // Dump All Section Headers
    for sh_header in sh_headers {
        sh_header.dump();

        let mut sh_addr = sh_header.sh_addr;
        if sh_header.sh_type == 0x1 {   // PROGBITS
            for byte_addr in (sh_header.sh_offset..(sh_header.sh_offset + sh_header.sh_size)) {
                let byte_data = loader.get_byte(byte_addr as usize);
                riscv_core.write_memory_byte(sh_addr as Addr64T, byte_data as Xlen64T);
                sh_addr += 1;
            }
        }
    }

これで、必要なセクションのみを選択してメモリにロードできるようになった。これでテストプログラムを動かしてみよう。

$ cargo run ${HOME}/riscv64/riscv64-unknown-elf/share/riscv-tests/isa/rv64ui-p-add
       459:M:Bare:0000800005d8:01e00113:addi       x02,x00,0x01e      :x00=>0000000000000000 x02<=000000000000001e
       460:M:Bare:0000800005dc:00208033:add        x00,x01,x02        :x01=>0000000000000010 x02=>000000000000001e
       461:M:Bare:0000800005e0:00000e93:addi       x29,x00,0x000      :x00=>0000000000000000 x29<=0000000000000000
       462:M:Bare:0000800005e4:02600193:addi       x03,x00,0x026      :x00=>0000000000000000 x03<=0000000000000026
       463:M:Bare:0000800005e8:01d01463:bne        x00,x29,0x8         :x00=>0000000000000000 x29=>0000000000000000
       464:M:Bare:0000800005ec:00301c63:bne        x00,x03,0x18        :x00=>0000000000000000 x03=>0000000000000026
       465:M:Bare:000080000604:0ff0000f:fence                         :
       466:M:Bare:000080000608:00100193:addi       x03,x00,0x001      :x00=>0000000000000000 x03<=0000000000000001
<Info: Generate Exception Code=11, TVAL=0000000000000000 PC=000000008000060c>
<Info: Exception. ChangeMode from 3 to 3>
<Info: Set Program Counter = 0x        80000004>
       467:M:Bare:00008000060c:00000073:ecall                         :
       468:M:Bare:000080000004:34202f73:csrrs      x30,0x342,x00      :x00=>0000000000000000 x30<=000000000000000b
       469:M:Bare:000080000008:00800f93:addi       x31,x00,0x008      :x00=>0000000000000000 x31<=0000000000000008
       470:M:Bare:00008000000c:03ff0a63:beq        x30,x31,0x34        :x30=>000000000000000b x31=>0000000000000008
       471:M:Bare:000080000010:00900f93:addi       x31,x00,0x009      :x00=>0000000000000000 x31<=0000000000000009
       472:M:Bare:000080000014:03ff0663:beq        x30,x31,0x2c        :x30=>000000000000000b x31=>0000000000000009
       473:M:Bare:000080000018:00b00f93:addi       x31,x00,0x00b      :x00=>0000000000000000 x31<=000000000000000b
       474:M:Bare:00008000001c:03ff0263:beq        x30,x31,0x24        :x30=>000000000000000b x31=>000000000000000b
       475:M:Bare:000080000040:00001f17:auipc      x30,0x00001        :x30<=0000000080001040
       476:M:Bare:000080000044:fc3f2023:sw         x03,0x0000fc0(x30) :x03=>0000000000000001 x30=>0000000080001040 (000080001000)<=0000000000000001
PASS : /home/msyksphinz/riscv64/riscv64-unknown-elf/share/riscv-tests/isa/rv64ui-p-add

動作したようだ。基本的な確認はこれで問題ない。

f:id:msyksphinz:20200811223154p:plain