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 */ }
ProgramHeader
とSectionHeader
には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); }
これで、もう少し詳細なヘッダの情報を出力するように改造する。