FPGA開発日記

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

RustでELFファイルを開く方法を調査する (4. リファクタリング)

RustでELFファイルを開いてダンプするプログラムを書いている。正しく動作するようになったところで、多少のリファクタリングを加えていく。

  • 情報に合わせてstructを定義する。ELFHeader, ProgramHeader, SectionHeaderを定義した。
pub struct ELFHeader {
    e_type      : EType,  /* Object file type */
    e_machine   : u16,  /* Architecture */
    e_version   : u32,  /* Object file version */
    e_entry     : u64,  /* Entry point virtual address */
    e_phoff     : u64,  /* Program header table file offset */
    e_shoff     : u64,  /* Section header table file offset */
    e_flags     : u32,  /* Processor-specific flags */
    e_ehsize    : u16,  /* ELF header size in bytes */
    e_phentsize : u16,  /* Program header table entry size */
    e_phnum     : u16,  /* Program header table entry count */
    e_shentsize : u16,  /* Section header table entry size */
    e_shnum     : u16,  /* Section header table entry count */
    e_shstrndx  : u16,  /* Section header string table index */
}


pub struct ProgramHeader<'a> {
    elf_header: &'a ELFHeader,

    p_type  : Phdr_Type,    /* entry type */
    p_flags : u32,          /* flags */
    p_offset: u64,          /* offset */
    p_vaddr : u64,          /* virtual address */
    p_paddr : u64,          /* physical address */
    p_filesz: u64,          /* file size */
    p_memsz : u64,          /* memory size */
    p_align : u64,          /* memory & file alignment */
}


pub struct SectionHeader<'a>
{
    elf_header: &'a ELFHeader,

    sh_name     : u32 ,        /* Section name (string tbl index) */
    sh_type     : u32 ,        /* Section type */
    sh_flags    : u64 ,        /* Section flags */
    sh_addr     : u64 ,        /* Section virtual addr at execution */
    sh_offset   : u64 ,        /* Section file offset */
    sh_size     : u64 ,        /* Section size in bytes */
    sh_link     : u32 ,        /* Link to another section */
    sh_info     : u32 ,        /* Additional section information */
    sh_addralign: u64 ,        /* Section alignment */
    sh_entsize  : u64 ,        /* Entry size if section holds table */
}

ProgramHeaderSectionHeaderにはELFHeaderの情報を持たせてある。ライフタイムの記述になれなくてしばらく悩んだ。ProgramHeaderを生成するためのget_program_header()は以下のようになっている。

    fn get_program_header<'a> (&self, elf_header: &'a ELFHeader,
                          e_phoff: u64, e_phentsize: u16, idx: u32) -> ProgramHeader<'a> {
        let mut ph_off = e_phoff;
        let ph_size    = e_phentsize as u32;

        ph_off += (ph_size*idx) as u64;

        let p_type   = self.get_4byte_elf(ph_off as usize); ph_off += 4;
        let p_flags  = self.get_4byte_elf(ph_off as usize); ph_off += 4;
        let p_offset = self.get_8byte_elf(ph_off as usize); ph_off += 8;
        let p_vaddr  = self.get_8byte_elf(ph_off as usize); ph_off += 8;
        let p_paddr  = self.get_8byte_elf(ph_off as usize); ph_off += 8;
        let p_filesz = self.get_8byte_elf(ph_off as usize); ph_off += 8;
        let p_memsz  = self.get_8byte_elf(ph_off as usize); ph_off += 8;
        let p_align  = self.get_8byte_elf(ph_off as usize); // ph_off += 8;

        let phdr_type = match Phdr_Type::from_u64(p_type as u64) {
            Some(phdr_type) => phdr_type,
            None            => panic!("Unknown Phdr Type"),
        };

        ProgramHeader::new (elf_header,
                            phdr_type, p_flags, p_offset, p_vaddr, p_paddr,
                            p_filesz, p_memsz, p_align)
    }

ライフタイムは、ELFHeaderのライフタイムとProgramHeaderのライフタイムが同一になるように設定した。これで合っているかな?

さらに、SectionHeaderのダンプ中にほかのSectionHeaderの情報を取得したいので、一度すべてのヘッダ情報をベクトルに纏めておくことにした。

    let mut ph_headers = Vec::new();
    for ph_idx in 0..elf_header.e_phnum {
        let phdr: ProgramHeader = loader.get_program_header(
            &elf_header,
            elf_header.e_phoff, elf_header.e_phentsize,
            ph_idx.into());
        ph_headers.push(phdr);
    }

    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);
    }

    // Dump All Program Headers
    for ph_header in ph_headers {
        ph_header.dump();
    }

    // Dump All Section Headers
    for sh_header in sh_headers {
        sh_header.dump();
        loader.dump_section(sh_header.sh_offset, sh_header.sh_size);
    }

これで、もう少し詳細なヘッダの情報を出力するように改造する。