1use alloc::vec::Vec;
2use core::ops::Deref;
3use core::ops::DerefMut;
4
5use crate::BlockRead;
6use crate::BlockWrite;
7use crate::ByteOrder;
8use crate::Class;
9use crate::ElfRead;
10use crate::ElfWrite;
11use crate::EntityIo;
12use crate::Error;
13
14#[derive(Debug)]
16#[cfg_attr(test, derive(PartialEq, Eq))]
17pub struct Rel {
18 pub offset: u64,
20 pub symbol: u32,
22 pub kind: u32,
24}
25
26impl Rel {
27 const fn info(&self, class: Class) -> u64 {
28 match class {
29 Class::Elf32 => ((self.symbol << 8) | (self.kind & 0xff)) as u64,
30 Class::Elf64 => ((self.symbol as u64) << 32) | self.kind as u64,
31 }
32 }
33}
34
35impl EntityIo for Rel {
36 fn read<R: ElfRead>(
37 reader: &mut R,
38 class: Class,
39 byte_order: ByteOrder,
40 ) -> Result<Self, Error> {
41 let offset;
42 let info;
43 match class {
44 Class::Elf32 => {
45 offset = reader.read_u32(byte_order)?.into();
46 info = reader.read_u32(byte_order)?.into();
47 }
48 Class::Elf64 => {
49 offset = reader.read_u64(byte_order)?;
50 info = reader.read_u64(byte_order)?;
51 }
52 }
53 let symbol = to_symbol(info, class);
54 let kind = to_kind(info, class);
55 Ok(Self {
56 offset,
57 symbol,
58 kind,
59 })
60 }
61
62 fn write<W: ElfWrite>(
63 &self,
64 writer: &mut W,
65 class: Class,
66 byte_order: ByteOrder,
67 ) -> Result<(), Error> {
68 let info = self.info(class);
69 match class {
70 Class::Elf32 => {
71 writer.write_u32_as_u64(byte_order, self.offset)?;
72 writer.write_u32_as_u64(byte_order, info)?;
73 }
74 Class::Elf64 => {
75 writer.write_u64(byte_order, self.offset)?;
76 writer.write_u64(byte_order, info)?;
77 }
78 }
79 Ok(())
80 }
81}
82
83#[derive(Debug)]
85#[cfg_attr(test, derive(PartialEq, Eq))]
86pub struct RelA {
87 pub rel: Rel,
89 pub addend: i64,
91}
92
93impl EntityIo for RelA {
94 fn read<R: ElfRead>(
95 reader: &mut R,
96 class: Class,
97 byte_order: ByteOrder,
98 ) -> Result<Self, Error> {
99 let rel = Rel::read(reader, class, byte_order)?;
100 let addend = match class {
101 Class::Elf32 => reader.read_i32(byte_order)?.into(),
102 Class::Elf64 => reader.read_i64(byte_order)?,
103 };
104 Ok(Self { rel, addend })
105 }
106
107 fn write<W: ElfWrite>(
108 &self,
109 writer: &mut W,
110 class: Class,
111 byte_order: ByteOrder,
112 ) -> Result<(), Error> {
113 self.rel.write(writer, class, byte_order)?;
114 match class {
115 Class::Elf32 => {
116 writer.write_i32_as_i64(byte_order, self.addend)?;
117 }
118 Class::Elf64 => {
119 writer.write_i64(byte_order, self.addend)?;
120 }
121 }
122 Ok(())
123 }
124}
125
126macro_rules! define_rel_table {
127 ($table: ident, $rel: ident, $rel_len: ident) => {
128 #[derive(Default)]
129 #[cfg_attr(test, derive(PartialEq, Eq, Debug))]
130 pub struct $table {
132 entries: Vec<$rel>,
133 }
134
135 impl $table {
136 pub fn new() -> Self {
138 Self::default()
139 }
140 }
141
142 impl BlockRead for $table {
143 fn read<R: ElfRead>(
144 reader: &mut R,
145 class: Class,
146 byte_order: ByteOrder,
147 len: u64,
148 ) -> Result<Self, Error> {
149 let mut entries = Vec::new();
150 let rel_len = class.$rel_len();
151 for _ in 0..len / rel_len as u64 {
152 let relocation = $rel::read(reader, class, byte_order)?;
153 entries.push(relocation);
154 }
155 Ok(Self { entries })
156 }
157 }
158
159 impl BlockWrite for $table {
160 fn write<W: ElfWrite>(
161 &self,
162 writer: &mut W,
163 class: Class,
164 byte_order: ByteOrder,
165 ) -> Result<(), Error> {
166 for relocation in self.entries.iter() {
167 relocation.write(writer, class, byte_order)?;
168 }
169 Ok(())
170 }
171 }
172
173 impl Deref for $table {
174 type Target = Vec<$rel>;
175 fn deref(&self) -> &Self::Target {
176 &self.entries
177 }
178 }
179
180 impl DerefMut for $table {
181 fn deref_mut(&mut self) -> &mut Self::Target {
182 &mut self.entries
183 }
184 }
185 };
186}
187
188define_rel_table!(RelTable, Rel, rel_len);
189define_rel_table!(RelaTable, RelA, rela_len);
190
191const fn to_symbol(info: u64, class: Class) -> u32 {
192 match class {
193 Class::Elf32 => (info as u32) >> 8,
194 Class::Elf64 => (info >> 32) as u32,
195 }
196}
197
198const fn to_kind(info: u64, class: Class) -> u32 {
199 match class {
200 Class::Elf32 => (info & 0xff) as u32,
201 Class::Elf64 => (info & 0xffff_ffff) as u32,
202 }
203}
204
205#[cfg(test)]
206mod tests {
207 use super::*;
208
209 use arbitrary::Unstructured;
210
211 use crate::constants::*;
212 use crate::test::test_block_io;
213 use crate::test::test_entity_io;
214 use crate::test::ArbitraryWithClass;
215
216 #[test]
217 fn relocation_io() {
218 test_entity_io::<Rel>();
219 }
220
221 #[test]
222 fn relocation_a_io() {
223 test_entity_io::<RelA>();
224 }
225
226 #[test]
227 fn relocation_table_io() {
228 test_block_io::<RelTable>();
229 }
230
231 #[test]
232 fn relocation_a_table_io() {
233 test_block_io::<RelaTable>();
234 }
235
236 impl ArbitraryWithClass<'_> for Rel {
237 fn arbitrary(u: &mut Unstructured<'_>, class: Class) -> arbitrary::Result<Self> {
238 Ok(match class {
239 Class::Elf32 => Self {
240 offset: u.arbitrary::<u32>()?.into(),
241 symbol: u.int_in_range(0..=0xff_ffff)?,
243 kind: u.arbitrary::<u8>()?.into(),
244 },
245 Class::Elf64 => Self {
246 offset: u.arbitrary()?,
247 symbol: u.arbitrary::<u32>()?,
248 kind: u.arbitrary::<u32>()?,
249 },
250 })
251 }
252 }
253
254 impl ArbitraryWithClass<'_> for RelA {
255 fn arbitrary(u: &mut Unstructured<'_>, class: Class) -> arbitrary::Result<Self> {
256 Ok(match class {
257 Class::Elf32 => Self {
258 rel: Rel::arbitrary(u, class)?,
259 addend: u.arbitrary::<i32>()?.into(),
260 },
261 Class::Elf64 => Self {
262 rel: Rel::arbitrary(u, class)?,
263 addend: u.arbitrary()?,
264 },
265 })
266 }
267 }
268
269 impl ArbitraryWithClass<'_> for RelTable {
270 fn arbitrary(u: &mut Unstructured<'_>, class: Class) -> arbitrary::Result<Self> {
271 let num_entries = u.arbitrary_len::<[u8; REL_LEN_64]>()?;
272 let mut entries = Vec::with_capacity(num_entries);
273 for _ in 0..num_entries {
274 entries.push(Rel::arbitrary(u, class)?);
275 }
276 Ok(Self { entries })
277 }
278 }
279
280 impl ArbitraryWithClass<'_> for RelaTable {
281 fn arbitrary(u: &mut Unstructured<'_>, class: Class) -> arbitrary::Result<Self> {
282 let num_entries = u.arbitrary_len::<[u8; RELA_LEN_64]>()?;
283 let mut entries = Vec::with_capacity(num_entries);
284 for _ in 0..num_entries {
285 entries.push(RelA::arbitrary(u, class)?);
286 }
287 Ok(Self { entries })
288 }
289 }
290}