elf_utilities/file/
elf32.rs

1use crate::{
2    header,
3    section::{self, Section32},
4    segment,
5};
6
7#[repr(C)]
8#[derive(Default, Clone, Hash, PartialOrd, Ord, PartialEq, Eq)]
9pub struct ELF32 {
10    pub ehdr: header::Ehdr32,
11    pub sections: Vec<section::Section32>,
12    pub segments: Vec<segment::Segment32>,
13}
14
15impl ELF32 {
16    /// add a section with creating new entry of section table and etc.
17    pub fn add_section(&mut self, mut sct: section::Section32) {
18        // ehdr.e_shstrndxの変更のために計算
19        let is_section_name_table = sct.name == ".shstrtab";
20
21        // 新しいセクションのsh_name等を計算する為に
22        // 現在の末尾のセクションを取得する
23        let last_sct_idx = self.sections.len() - 1;
24        self.fill_elf_info(&mut sct, last_sct_idx, &self.sections[last_sct_idx]);
25
26        // セクションの追加 => SHTの開始オフセットが変更される
27        self.ehdr.e_shoff += sct.header.sh_size;
28        self.ehdr.e_shnum += 1;
29
30        self.sections.push(sct);
31
32        if is_section_name_table {
33            self.ehdr.e_shstrndx = self.sections.len() as u16 - 1;
34        }
35    }
36
37    pub fn add_segment(&mut self, sgt: segment::Segment32) {
38        // PHTに追加される => SHTのオフセットと各セクションのオフセットが変更される
39        self.ehdr.e_shoff += segment::Phdr32::SIZE as u32;
40        for sct in self.sections.iter_mut() {
41            sct.header.sh_offset += segment::Phdr32::SIZE as u32;
42        }
43        self.ehdr.e_phnum += 1;
44
45        self.segments.push(sgt);
46    }
47    pub fn to_le_bytes(&self) -> Vec<u8> {
48        let mut file_binary: Vec<u8> = Vec::new();
49
50        let mut header_binary = self.ehdr.to_le_bytes();
51        file_binary.append(&mut header_binary);
52
53        for seg in self.segments.iter() {
54            let mut phdr_binary = seg.header.to_le_bytes();
55            file_binary.append(&mut phdr_binary);
56        }
57
58        let mut sections = self.sections.clone();
59        sections.sort_by_key(|sct| sct.header.sh_offset);
60        for sct in self.sections.iter() {
61            let mut section_binary = sct.to_le_bytes();
62
63            if sct.header.sh_addralign > 1 && file_binary.len() != sct.header.sh_offset as usize {
64                file_binary.append(&mut vec![0x00; sct.header.sh_offset as usize - file_binary.len()]);
65            }
66
67            file_binary.append(&mut section_binary);
68        }
69
70        if file_binary.len() < self.ehdr.e_shoff as usize {
71            file_binary.append(&mut vec![0x00; self.ehdr.e_shoff as usize - file_binary.len()]);
72        }
73
74        for sct in self.sections.iter() {
75            let mut shdr_binary = sct.header.to_le_bytes();
76            file_binary.append(&mut shdr_binary);
77        }
78        file_binary
79    }
80
81    /// sh_nameやsh_offset等の調整
82    fn fill_elf_info(&self, new_sct: &mut Section32, prev_sct_idx: usize, prev_sct: &Section32) {
83        let prev_name_idx = prev_sct.header.sh_name;
84        let prev_name_len = prev_sct.name.as_bytes().len() as u32;
85        let prev_offset = prev_sct.header.sh_offset;
86        let prev_size = prev_sct.header.sh_size;
87
88        // <prev_section_name> の後に0x00が入るので,+1
89        new_sct.header.sh_name = prev_name_idx + prev_name_len + 1;
90
91        // NULLセクションのすぐ次に挿入する場合,
92        // sh_offsetはEhdr32::SIZE + PHT's SIZEという感じになる.
93        if prev_sct_idx == 0 {
94            new_sct.header.sh_offset = header::Ehdr32::SIZE as u32
95                + segment::Phdr32::SIZE as u32 * self.segments.len() as u32;
96        } else {
97            new_sct.header.sh_offset = prev_offset + prev_size;
98        }
99
100        new_sct.header.sh_size = new_sct.contents.size() as u32;
101    }
102}