Rustを使うなら何を作ってみたいって、並列性をうまく利用してメニーコアのシミュレータとかを作るのが、CPUアーキテクチャの勉強にとっても、Rustの勉強にとっても良さそうだ。
でも、RustでElfファイルを扱う方法ってあるのか?いろいろと調べていると、ライブラリはあるらしい。
今回調査したのは goblin
というライブラリで、 elfファイルをParseしてくれるらしい。
いくつかこれを使ったサンプルプログラムが存在しているが、RustはVerilogやChiselと同じく、ほとんど情報が無い。少し流行っているとはいえ、やはり情報収集は大変だなあ。。。
バイナリファイルを読み込んで、シンボル情報を読み込む
goblinというライブラリを使うと、バイナリファイルを解析することが出来る。試しにRustでプログラムを書いてみた。
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でいくつか探すと、以下のサンプルプログラムが出てきた。
elfの情報からセクションヘッダとシンボルテーブルを読み込んでprintln()
で出力している。 symbol.st_name
や section.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