monistode_binutils/object_file/sections/
header.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
use crate::serializable::{Serializable, SerializationError};

#[derive(Debug, Clone)]
pub enum SectionType {
    Text,
    SymbolTable,
    RelocationTable,
}

impl TryFrom<u8> for SectionType {
    type Error = SerializationError;

    fn try_from(value: u8) -> Result<Self, Self::Error> {
        match value {
            0 => Ok(SectionType::Text),
            255 => Ok(SectionType::SymbolTable),
            254 => Ok(SectionType::RelocationTable),
            v => Err(SerializationError::InvalidSectionType(v)),
        }
    }
}

impl From<SectionType> for u8 {
    fn from(value: SectionType) -> Self {
        match value {
            SectionType::Text => 0,
            SectionType::SymbolTable => 255,
            SectionType::RelocationTable => 254,
        }
    }
}

#[derive(Debug, Clone)]
pub struct TextSectionHeader {
    pub bit_length: usize,
}

#[derive(Debug, Clone)]
pub struct SymbolTableHeader {
    pub entry_count: u32,
    pub names_length: u32,
}

#[derive(Debug, Clone)]
pub struct RelocationTableHeader {
    pub entry_count: u32,
    pub names_length: u32,
}

#[derive(Debug, Clone)]
pub enum SectionHeader {
    Text(TextSectionHeader),
    SymbolTable(SymbolTableHeader),
    RelocationTable(RelocationTableHeader),
}

impl Serializable for SectionHeader {
    fn serialize(&self) -> Vec<u8> {
        let mut data = Vec::with_capacity(16);
        match self {
            SectionHeader::Text(header) => {
                data.push(SectionType::Text.into());
                data.extend([0; 7]); // Padding to 8 bytes
                data.extend(header.bit_length.to_le_bytes());
            }
            SectionHeader::SymbolTable(header) => {
                data.push(SectionType::SymbolTable.into());
                data.extend([0; 3]); // Padding to 4 bytes
                data.extend(header.entry_count.to_le_bytes());
                data.extend(header.names_length.to_le_bytes());
                data.extend([0; 4]); // Padding to 16 bytes
            }
            SectionHeader::RelocationTable(header) => {
                data.push(SectionType::RelocationTable.into());
                data.extend([0; 3]); // Padding to 4 bytes
                data.extend(header.entry_count.to_le_bytes());
                data.extend(header.names_length.to_le_bytes());
                data.extend([0; 4]); // Padding to 16 bytes
            }
        }
        data
    }

    fn deserialize(data: &[u8]) -> Result<(usize, Self), SerializationError> {
        if data.len() < 16 {
            return Err(SerializationError::DataTooShort);
        }

        match data[0] {
            0 => {
                let bit_length = u64::from_le_bytes([
                    data[8], data[9], data[10], data[11], data[12], data[13], data[14], data[15],
                ]) as usize;
                Ok((16, SectionHeader::Text(TextSectionHeader { bit_length })))
            }
            255 | 254 => {
                let entry_count = u32::from_le_bytes([data[4], data[5], data[6], data[7]]);
                let names_length = u32::from_le_bytes([data[8], data[9], data[10], data[11]]);
                let header = if data[0] == 255 {
                    SectionHeader::SymbolTable(SymbolTableHeader {
                        entry_count,
                        names_length,
                    })
                } else {
                    SectionHeader::RelocationTable(RelocationTableHeader {
                        entry_count,
                        names_length,
                    })
                };
                Ok((16, header))
            }
            v => Err(SerializationError::InvalidSectionType(v)),
        }
    }
}

impl SectionHeader {
    pub fn section_size(&self) -> u64 {
        match self {
            SectionHeader::Text(header) => (header.bit_length as u64 + 7) / 8,
            SectionHeader::SymbolTable(header) => {
                (header.entry_count as u64 * 12) + header.names_length as u64
            }
            SectionHeader::RelocationTable(header) => {
                (header.entry_count as u64 * 16) + header.names_length as u64
            }
        }
    }
}