elb/
relocations.rs

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/// Relocation without an addend.
15#[derive(Debug)]
16#[cfg_attr(test, derive(PartialEq, Eq))]
17pub struct Rel {
18    /// The offset from the beginning of the section.
19    pub offset: u64,
20    /// Symbol index.
21    pub symbol: u32,
22    /// Relocation type.
23    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/// Relocation with an addend.
84#[derive(Debug)]
85#[cfg_attr(test, derive(PartialEq, Eq))]
86pub struct RelA {
87    /// Relocation without an addend.
88    pub rel: Rel,
89    /// The constant addend.
90    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        /// Relocation table.
131        pub struct $table {
132            entries: Vec<$rel>,
133        }
134
135        impl $table {
136            /// Create empty table.
137            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                    // 24 bits
242                    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}