monistode_binutils/executable/
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
pub use header::ExecutableHeader;
pub use segments::{Segment, SegmentHeader};

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

pub mod header;
pub mod segments;

#[derive(Debug, Clone)]
pub struct Executable {
    header: ExecutableHeader,
    segments: Vec<Segment>,
}

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

        // Optionally create symbol table from segment data - using the same section based table
        // because why not
        let mut symbol_table = SymbolTable::new();

        for (segment_id, segment) in self.segments.iter().enumerate() {
            for symbol in segment.symbols() {
                symbol_table.add_symbol(segment_id as u32, symbol);
            }
        }

        // Serialize header with all segments (including symbol table)
        let header = ExecutableHeader {
            architecture: self.header.architecture,
            segment_count: self.segments.len() as u64 + 1, // +1 for symbol table
            entry_point: self.header.entry_point,
        };
        data.extend(header.serialize());

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

        // Add regular segment headers first
        for segment in &self.segments {
            let (header, bytes) = segment.serialize();
            headers.push(header);
            segment_data.extend(bytes);
        }

        // Add symbol table headers last
        let (symbol_header, symbol_data) = symbol_table.serialize_as_segment();
        headers.push(symbol_header);
        segment_data.extend(symbol_data);

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

        data
    }

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

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

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

        // Last segment must be symbol table - TODO optional
        let segment_count = headers.len();
        if segment_count < 1 {
            return Err(SerializationError::InvalidData);
        }
        if !headers[segment_count - 1].flags.special
            || !headers[segment_count - 1].address_space_start == 0
        {
            return Err(SerializationError::InvalidData);
        }

        // Ensure no other symbol table segments exist
        if headers[..segment_count - 1]
            .iter()
            .any(|h| h.flags.special && h.address_space_start == 0)
        {
            return Err(SerializationError::InvalidData);
        }

        // Calculate offsets to symbol and relocation tables
        let mut segment_data_offset = offset;
        for header in &headers[..segment_count - 1] {
            segment_data_offset += header.segment_size();
        }

        // Load symbol table first
        let symbol_offset = segment_data_offset;
        let (_, symbol_table) =
            SymbolTable::deserialize_segment(&headers[segment_count - 1], &data[symbol_offset..])?;

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

        for (idx, segment_header) in headers[..segment_count - 1].iter().enumerate() {
            let symbols = symbol_table.get_symbols(idx as u32);
            let (size, segment) =
                Segment::deserialize(segment_header, &data[current_offset..], symbols)?;
            segments.push(segment);
            current_offset += size;
        }

        Ok((
            symbol_offset + headers[segment_count - 1].segment_size(), // TODO sure?
            Executable { header, segments },
        ))
    }
}

impl Executable {
    pub fn new(architecture: Architecture, segments: Vec<Segment>) -> Self {
        Executable {
            header: ExecutableHeader::new(architecture, 0),
            segments,
        }
    }

    pub fn segments(&self) -> &[Segment] {
        &self.segments
    }

    pub fn segments_mut(&mut self) -> &mut Vec<Segment> {
        &mut self.segments
    }

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

    pub fn entry_point(&self) -> u64 {
        self.header.entry_point
    }
}