monistode_binutils/object_file/
relocations.rs

1use super::sections::header::{RelocationTableHeader, SectionHeader};
2use crate::serializable::*;
3use crate::Address;
4
5#[derive(Debug, Clone)]
6pub struct Relocation {
7    pub symbol: String,
8    pub address: Address,
9    pub relative: bool,
10}
11
12#[derive(Debug, Clone)]
13struct RelocationEntry {
14    section_id: u32,
15    symbol_offset: usize,
16    address: Address,
17    relative: bool,
18}
19
20#[derive(Debug, Clone)]
21pub struct RelocationTable {
22    entries: Vec<RelocationEntry>,
23    names: Vec<u8>,
24}
25
26impl RelocationTable {
27    pub fn new() -> Self {
28        RelocationTable {
29            entries: Vec::new(),
30            names: Vec::new(),
31        }
32    }
33
34    pub fn add_relocation(&mut self, section_id: u32, relocation: Relocation) {
35        let symbol_offset = self.names.len();
36        self.names.extend(relocation.symbol.as_bytes());
37        self.names.push(0); // null terminator
38
39        self.entries.push(RelocationEntry {
40            section_id,
41            symbol_offset,
42            address: relocation.address,
43            relative: relocation.relative,
44        });
45    }
46
47    pub fn serialize(&self) -> (SectionHeader, Vec<u8>) {
48        let mut data = Vec::new();
49
50        // Entries
51        for entry in &self.entries {
52            data.extend(entry.section_id.to_le_bytes());
53            data.extend((entry.symbol_offset as u32).to_le_bytes());
54            data.extend((entry.address.0 as u32).to_le_bytes());
55            data.push(entry.relative as u8);
56            data.push(0); // padding for alignment
57            data.push(0);
58            data.push(0);
59        }
60
61        // Names
62        data.extend(&self.names);
63
64        let header = SectionHeader::RelocationTable(RelocationTableHeader {
65            entry_count: self.entries.len() as u32,
66            names_length: self.names.len() as u32,
67        });
68
69        (header, data)
70    }
71
72    pub fn deserialize(
73        header: &RelocationTableHeader,
74        data: &[u8],
75    ) -> Result<(usize, Self), SerializationError> {
76        let required_size = (header.entry_count as usize * 16) + header.names_length as usize;
77        if data.len() < required_size {
78            return Err(SerializationError::DataTooShort);
79        }
80
81        let mut offset = 0;
82        let mut entries = Vec::new();
83
84        // Read entries
85        for _ in 0..header.entry_count {
86            if offset + 16 > data.len() {
87                return Err(SerializationError::DataTooShort);
88            }
89
90            let section_id = u32::from_le_bytes([
91                data[offset],
92                data[offset + 1],
93                data[offset + 2],
94                data[offset + 3],
95            ]);
96            offset += 4;
97
98            let symbol_offset = u32::from_le_bytes([
99                data[offset],
100                data[offset + 1],
101                data[offset + 2],
102                data[offset + 3],
103            ]) as usize;
104            offset += 4;
105
106            let addr = u32::from_le_bytes([
107                data[offset],
108                data[offset + 1],
109                data[offset + 2],
110                data[offset + 3],
111            ]) as usize;
112            offset += 4;
113
114            let relative = data[offset] != 0;
115            offset += 4; // Skip padding bytes too
116
117            if symbol_offset >= header.names_length as usize {
118                return Err(SerializationError::InvalidData);
119            }
120
121            entries.push(RelocationEntry {
122                section_id,
123                symbol_offset,
124                address: Address(addr),
125                relative,
126            });
127        }
128
129        // Read names
130        if offset + header.names_length as usize > data.len() {
131            return Err(SerializationError::DataTooShort);
132        }
133        let names = data[offset..offset + header.names_length as usize].to_vec();
134
135        // Validate that all names are properly null-terminated
136        if names.len() > 0 {
137            if !names.iter().any(|&b| b == 0) {
138                return Err(SerializationError::InvalidData);
139            }
140        }
141
142        Ok((
143            offset + header.names_length as usize,
144            RelocationTable { entries, names },
145        ))
146    }
147
148    pub fn get_relocations(&self, section_id: u32) -> Vec<Relocation> {
149        self.entries
150            .iter()
151            .filter(|entry| entry.section_id == section_id)
152            .map(|entry| {
153                let mut symbol = String::new();
154                let mut i = entry.symbol_offset as usize;
155                while i < self.names.len() && self.names[i] != 0 {
156                    symbol.push(self.names[i] as char);
157                    i += 1;
158                }
159                Relocation {
160                    symbol,
161                    address: Address(entry.address.0),
162                    relative: entry.relative,
163                }
164            })
165            .collect()
166    }
167}