elf/
relocation.rs

1//! Parsing relocation sections: `.rel.*`, `.rela.*`, [SHT_REL](crate::abi::SHT_REL), [SHT_RELA](crate::abi::SHT_RELA)
2use crate::endian::EndianParse;
3use crate::file::Class;
4use crate::parse::{ParseAt, ParseError, ParsingIterator};
5
6pub type RelIterator<'data, E> = ParsingIterator<'data, E, Rel>;
7pub type RelaIterator<'data, E> = ParsingIterator<'data, E, Rela>;
8
9/// C-style 32-bit ELF Relocation definition
10///
11/// These C-style definitions are for users who want to implement their own ELF manipulation logic.
12#[derive(Debug)]
13#[repr(C)]
14pub struct Elf32_Rel {
15    pub r_offset: u32,
16    pub r_info: u32,
17}
18
19/// C-style 64-bit ELF Relocation definition
20///
21/// These C-style definitions are for users who want to implement their own ELF manipulation logic.
22#[derive(Debug)]
23#[repr(C)]
24pub struct Elf64_Rel {
25    pub r_offset: u64,
26    pub r_info: u64,
27}
28
29#[derive(Debug, Clone, PartialEq, Eq)]
30pub struct Rel {
31    pub r_offset: u64,
32    pub r_sym: u32,
33    pub r_type: u32,
34}
35
36impl ParseAt for Rel {
37    fn parse_at<E: EndianParse>(
38        endian: E,
39        class: Class,
40        offset: &mut usize,
41        data: &[u8],
42    ) -> Result<Self, ParseError> {
43        match class {
44            Class::ELF32 => {
45                let r_offset = endian.parse_u32_at(offset, data)? as u64;
46                let r_info = endian.parse_u32_at(offset, data)?;
47                Ok(Rel {
48                    r_offset,
49                    r_sym: r_info >> 8,
50                    r_type: r_info & 0xFF,
51                })
52            }
53            Class::ELF64 => {
54                let r_offset = endian.parse_u64_at(offset, data)?;
55                let r_info = endian.parse_u64_at(offset, data)?;
56                Ok(Rel {
57                    r_offset,
58                    r_sym: (r_info >> 32) as u32,
59                    r_type: (r_info & 0xFFFFFFFF) as u32,
60                })
61            }
62        }
63    }
64
65    #[inline]
66    fn size_for(class: Class) -> usize {
67        match class {
68            Class::ELF32 => 8,
69            Class::ELF64 => 16,
70        }
71    }
72}
73
74/// C-style 32-bit ELF Relocation (with addend) definition
75///
76/// These C-style definitions are for users who want to implement their own ELF manipulation logic.
77#[derive(Debug)]
78#[repr(C)]
79pub struct Elf32_Rela {
80    pub r_offset: u32,
81    pub r_info: u32,
82    pub r_addend: i32,
83}
84
85/// C-style 64-bit ELF Relocation (with addend) definition
86///
87/// These C-style definitions are for users who want to implement their own ELF manipulation logic.
88#[derive(Debug)]
89#[repr(C)]
90pub struct Elf64_Rela {
91    pub r_offset: u64,
92    pub r_info: u64,
93    pub r_addend: i64,
94}
95
96#[derive(Debug, Clone, PartialEq, Eq)]
97pub struct Rela {
98    pub r_offset: u64,
99    pub r_sym: u32,
100    pub r_type: u32,
101    pub r_addend: i64,
102}
103
104impl ParseAt for Rela {
105    fn parse_at<E: EndianParse>(
106        endian: E,
107        class: Class,
108        offset: &mut usize,
109        data: &[u8],
110    ) -> Result<Self, ParseError> {
111        match class {
112            Class::ELF32 => {
113                let r_offset = endian.parse_u32_at(offset, data)? as u64;
114                let r_info = endian.parse_u32_at(offset, data)?;
115                let r_addend = endian.parse_i32_at(offset, data)? as i64;
116                Ok(Rela {
117                    r_offset,
118                    r_sym: r_info >> 8,
119                    r_type: r_info & 0xFF,
120                    r_addend,
121                })
122            }
123            Class::ELF64 => {
124                let r_offset = endian.parse_u64_at(offset, data)?;
125                let r_info = endian.parse_u64_at(offset, data)?;
126                let r_addend = endian.parse_i64_at(offset, data)?;
127                Ok(Rela {
128                    r_offset,
129                    r_sym: (r_info >> 32) as u32,
130                    r_type: (r_info & 0xFFFFFFFF) as u32,
131                    r_addend,
132                })
133            }
134        }
135    }
136
137    #[inline]
138    fn size_for(class: Class) -> usize {
139        match class {
140            Class::ELF32 => 12,
141            Class::ELF64 => 24,
142        }
143    }
144}
145
146#[cfg(test)]
147mod parse_tests {
148    use super::*;
149    use crate::endian::{BigEndian, LittleEndian};
150    use crate::parse::{test_parse_for, test_parse_fuzz_too_short};
151
152    #[test]
153    fn parse_rel32_lsb() {
154        test_parse_for(
155            LittleEndian,
156            Class::ELF32,
157            Rel {
158                r_offset: 0x03020100,
159                r_sym: 0x00070605,
160                r_type: 0x00000004,
161            },
162        );
163    }
164
165    #[test]
166    fn parse_rel32_msb() {
167        test_parse_for(
168            BigEndian,
169            Class::ELF32,
170            Rel {
171                r_offset: 0x00010203,
172                r_sym: 0x00040506,
173                r_type: 0x00000007,
174            },
175        );
176    }
177
178    #[test]
179    fn parse_rel64_lsb() {
180        test_parse_for(
181            LittleEndian,
182            Class::ELF64,
183            Rel {
184                r_offset: 0x0706050403020100,
185                r_sym: 0x0F0E0D0C,
186                r_type: 0x0B0A0908,
187            },
188        );
189    }
190
191    #[test]
192    fn parse_rel64_msb() {
193        test_parse_for(
194            BigEndian,
195            Class::ELF64,
196            Rel {
197                r_offset: 0x0001020304050607,
198                r_sym: 0x08090A0B,
199                r_type: 0x0C0D0E0F,
200            },
201        );
202    }
203
204    #[test]
205    fn parse_rel32_lsb_fuzz_too_short() {
206        test_parse_fuzz_too_short::<_, Rel>(LittleEndian, Class::ELF32);
207    }
208
209    #[test]
210    fn parse_rel32_msb_fuzz_too_short() {
211        test_parse_fuzz_too_short::<_, Rel>(BigEndian, Class::ELF32);
212    }
213
214    #[test]
215    fn parse_rel64_lsb_fuzz_too_short() {
216        test_parse_fuzz_too_short::<_, Rel>(LittleEndian, Class::ELF64);
217    }
218
219    #[test]
220    fn parse_rel64_msb_fuzz_too_short() {
221        test_parse_fuzz_too_short::<_, Rel>(BigEndian, Class::ELF64);
222    }
223
224    #[test]
225    fn parse_rela32_lsb() {
226        test_parse_for(
227            LittleEndian,
228            Class::ELF32,
229            Rela {
230                r_offset: 0x03020100,
231                r_sym: 0x00070605,
232                r_type: 0x00000004,
233                r_addend: 0x0B0A0908,
234            },
235        );
236    }
237
238    #[test]
239    fn parse_rela32_msb() {
240        test_parse_for(
241            BigEndian,
242            Class::ELF32,
243            Rela {
244                r_offset: 0x00010203,
245                r_sym: 0x00040506,
246                r_type: 0x00000007,
247                r_addend: 0x08090A0B,
248            },
249        );
250    }
251
252    #[test]
253    fn parse_rela64_lsb() {
254        test_parse_for(
255            LittleEndian,
256            Class::ELF64,
257            Rela {
258                r_offset: 0x0706050403020100,
259                r_sym: 0x0F0E0D0C,
260                r_type: 0x0B0A0908,
261                r_addend: 0x1716151413121110,
262            },
263        );
264    }
265
266    #[test]
267    fn parse_rela64_msb() {
268        test_parse_for(
269            BigEndian,
270            Class::ELF64,
271            Rela {
272                r_offset: 0x0001020304050607,
273                r_sym: 0x08090A0B,
274                r_type: 0x0C0D0E0F,
275                r_addend: 0x1011121314151617,
276            },
277        );
278    }
279
280    #[test]
281    fn parse_rela32_lsb_fuzz_too_short() {
282        test_parse_fuzz_too_short::<_, Rela>(LittleEndian, Class::ELF32);
283    }
284
285    #[test]
286    fn parse_rela32_msb_fuzz_too_short() {
287        test_parse_fuzz_too_short::<_, Rela>(BigEndian, Class::ELF32);
288    }
289
290    #[test]
291    fn parse_rela64_lsb_fuzz_too_short() {
292        test_parse_fuzz_too_short::<_, Rela>(LittleEndian, Class::ELF64);
293    }
294
295    #[test]
296    fn parse_rela64_msb_fuzz_too_short() {
297        test_parse_fuzz_too_short::<_, Rela>(BigEndian, Class::ELF64);
298    }
299}