FPGA開発日記

FPGAというより、コンピュータアーキテクチャかもね! カテゴリ別記事インデックス https://sites.google.com/site/fpgadevelopindex/

プログラミング言語Rustに入門中 (goblinを使ってelfファイルを解析する)

f:id:msyksphinz:20171103203951p:plain

Rustを使うなら何を作ってみたいって、並列性をうまく利用してメニーコアのシミュレータとかを作るのが、CPUアーキテクチャの勉強にとっても、Rustの勉強にとっても良さそうだ。

でも、RustでElfファイルを扱う方法ってあるのか?いろいろと調べていると、ライブラリはあるらしい。 今回調査したのは goblin というライブラリで、 elfファイルをParseしてくれるらしい。

goblin 0.0.12 - Docs.rs

いくつかこれを使ったサンプルプログラムが存在しているが、RustはVerilogやChiselと同じく、ほとんど情報が無い。少し流行っているとはいえ、やはり情報収集は大変だなあ。。。

バイナリファイルを読み込んで、シンボル情報を読み込む

goblinというライブラリを使うと、バイナリファイルを解析することが出来る。試しにRustでプログラムを書いてみた。

github.com

            match Object::parse(&buffer)? {
                Object::Elf(elf) => {
                    // println!("elf: {:#?}", &elf);
                    for header in &elf.program_headers {
                        println!("elf.program_headers = {:#?}", header);
                    }
                    let shdr_strtab = &elf.shdr_strtab;
                    for section in &elf.section_headers {
                        println!("elf.section_headers = {:#?}", &shdr_strtab[section.sh_name]);
                    }
                    let sym_strtab = &elf.strtab;
                    for symbol in &elf.syms {
                        println!("elf.symbol = {:#?} {:#x}", &sym_strtab[symbol.st_name], symbol.st_value);
                    }
                }

情報が無さ過ぎて大変なので、githubでいくつか探すと、以下のサンプルプログラムが出てきた。

github.com

elfの情報からセクションヘッダとシンボルテーブルを読み込んでprintln()で出力している。 symbol.st_namesection.sh_nameはシンボルテーブルに対するインデックスに過ぎないので、配列を参照してシンボル情報を出力する。

$ cargo run ~/work/rocket-chip-msyksphinz/riscv-tools/riscv-tests/benchmarks/qsort.riscv
...
elf.symbol = "_tls_data" 0x80005b80
elf.symbol = "abort" 0x800015c6
elf.symbol = "_init" 0x80001774
elf.symbol = "setStats" 0x8000154e
elf.symbol = "strnlen" 0x80001850
elf.symbol = "sort" 0x80001086
elf.symbol = "_start" 0x80000000
elf.symbol = "memset" 0x8000172e
elf.symbol = "main" 0x80001908
elf.symbol = "strcmp" 0x80001872
elf.symbol = "sprintf" 0x800016ac
elf.symbol = "printhex" 0x80001634
elf.symbol = "_tdata_end" 0x0
elf.symbol = "_end" 0x80005b80
elf.symbol = "fromhost" 0x80001040
elf.symbol = "_tdata_begin" 0x0
elf.symbol = "tohost" 0x80001000
elf.symbol = "exit" 0x800015be
elf.symbol = "tohost_exit" 0x8000159c
elf.symbol = "verify_data" 0x80001b38
elf.symbol = "_tbss_end" 0x44
elf.symbol = "strlen" 0x80001838
elf.symbol = "thread_entry" 0x8000162e