monistode_binutils/object_file/
mod.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
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
pub mod header;
pub mod placed;
pub mod relocations;
pub mod sections;

pub use header::ObjectHeader;
pub use relocations::{Relocation, RelocationTable};
pub use sections::*;

use crate::{Architecture, Serializable, SerializationError, SymbolTable};

#[derive(Debug, Clone)]
pub struct ObjectFile {
    architecture: Architecture,
    sections: Vec<Section>,
}

impl Serializable for ObjectFile {
    fn serialize(&self) -> Vec<u8> {
        let mut data = Vec::new();

        // Create symbol and relocation tables from section data
        let mut symbol_table = SymbolTable::new();
        let mut relocation_table = RelocationTable::new();

        for (section_id, section) in self.sections.iter().enumerate() {
            for symbol in section.symbols() {
                symbol_table.add_symbol(section_id as u32, symbol);
            }
            for relocation in section.relocations() {
                relocation_table.add_relocation(section_id as u32, relocation);
            }
        }

        // Serialize header with all sections (including symbol and relocation tables)
        let header = ObjectHeader {
            architecture: self.architecture,
            section_count: self.sections.len() as u64 + 2, // +2 for symbol and relocation tables
        };
        data.extend(header.serialize());

        // Create and serialize all section headers and data
        let mut section_data = Vec::new();
        let mut headers = Vec::new();

        // Add regular section headers first
        for section in &self.sections {
            let (header, bytes) = section.serialize();
            headers.push(header);
            section_data.extend(bytes);
        }

        // Add symbol and relocation table headers last
        let (symbol_header, symbol_data) = symbol_table.serialize_as_section();
        let (relocation_header, relocation_data) = relocation_table.serialize();
        headers.push(symbol_header);
        headers.push(relocation_header);
        section_data.extend(symbol_data);
        section_data.extend(relocation_data);

        // Add all headers followed by all section data
        for header in headers {
            data.extend(header.serialize());
        }
        data.extend(section_data);

        data
    }

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

        // Parse header
        let (header_size, header) = ObjectHeader::deserialize(data)?;
        let mut offset = header_size;

        // Read all section headers
        let mut headers = Vec::new();
        for _ in 0..header.section_count {
            if data.len() < offset + 16 {
                // Minimum section header size
                return Err(SerializationError::DataTooShort);
            }
            let (size, section_header) = SectionHeader::deserialize(&data[offset..])?;
            headers.push(section_header);
            offset += size;
        }

        // Last two sections must be symbol table and relocation table
        let section_count = headers.len();
        if section_count < 2 {
            return Err(SerializationError::InvalidData);
        }
        if !matches!(headers[section_count - 2], SectionHeader::SymbolTable(_)) {
            return Err(SerializationError::InvalidData);
        }
        if !matches!(
            headers[section_count - 1],
            SectionHeader::RelocationTable(_)
        ) {
            return Err(SerializationError::InvalidData);
        }

        // Ensure no other symbol/relocation table sections exist
        if headers[..section_count - 2].iter().any(|h| {
            matches!(
                h,
                SectionHeader::SymbolTable(_) | SectionHeader::RelocationTable(_)
            )
        }) {
            return Err(SerializationError::InvalidData);
        }

        // Calculate offsets to symbol and relocation tables
        let mut section_data_offset = offset;
        for header in &headers[..section_count - 2] {
            section_data_offset += header.section_size() as usize;
        }

        // Load symbol and relocation tables first
        let symbol_offset = section_data_offset;
        let (_, symbol_table) = SymbolTable::deserialize_section(
            match &headers[section_count - 2] {
                SectionHeader::SymbolTable(h) => h,
                _ => unreachable!(),
            },
            &data[symbol_offset..],
        )?;

        let relocation_offset = symbol_offset + headers[section_count - 2].section_size() as usize;
        let (_, relocation_table) = RelocationTable::deserialize(
            match &headers[section_count - 1] {
                SectionHeader::RelocationTable(h) => h,
                _ => unreachable!(),
            },
            &data[relocation_offset..],
        )?;

        // Process regular sections
        let mut sections = Vec::new();
        let mut current_offset = offset;

        for (idx, section_header) in headers[..section_count - 2].iter().enumerate() {
            match section_header {
                SectionHeader::Text(_) => {
                    let symbols = symbol_table.get_symbols(idx as u32);
                    let relocations = relocation_table.get_relocations(idx as u32);
                    let (size, section) = Section::deserialize(
                        section_header,
                        &data[current_offset..],
                        symbols,
                        relocations,
                    )?;
                    sections.push(section);
                    current_offset += size;
                }
                _ => return Err(SerializationError::InvalidData),
            }
        }

        Ok((
            relocation_offset + headers[section_count - 1].section_size() as usize,
            ObjectFile {
                architecture: header.architecture,
                sections,
            },
        ))
    }
}

impl ObjectFile {
    pub fn new(architecture: Architecture) -> Self {
        ObjectFile {
            architecture,
            sections: Vec::new(),
        }
    }

    pub fn with_sections(architecture: Architecture, sections: Vec<Section>) -> Self {
        ObjectFile {
            architecture,
            sections,
        }
    }

    pub fn add_section(&mut self, section: Section) {
        self.sections.push(section);
    }

    pub fn sections(self) -> Vec<Section> {
        self.sections
    }

    pub fn architecture(&self) -> Architecture {
        self.architecture
    }

    pub fn merge(&mut self, other: ObjectFile) {
        if self.architecture != other.architecture {
            panic!("Cannot merge object files with different architectures");
        }
        self.sections.extend(other.sections);
    }
}