monistode_binutils/object_file/
relocations.rs1use 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); 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 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); data.push(0);
58 data.push(0);
59 }
60
61 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 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; 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 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 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}