1use crate::io::{Endian, ReadExt, WriteExt};
2use num_derive::FromPrimitive;
3use num_traits::FromPrimitive;
4use std::io::{Read, Write};
5
6#[derive(Debug, Clone, Copy, PartialEq, Eq)]
7pub struct RelocationInfo {
8 pub r_address: i32,
11 pub r_symbolnum: u32,
15 pub r_pcrel: bool,
21 pub r_length: RelocLength,
22 pub r_extern: bool,
26 pub r_type: u8,
28}
29
30impl RelocationInfo {
31 pub const SIZE: u32 = 8;
33
34 pub fn read_from_in<R: Read>(read: &mut R, endian: Endian) -> RelocationInfo {
35 let r_address = read.read_i32_in(endian);
36
37 let infos = read.read_u32_in(endian);
38
39 let (r_symbolnum, r_pcrel, r_length, r_extern, r_type) = if endian == Endian::Little {
44 (
45 infos & 0x00FF_FFFF,
47 (infos & 0x0100_0000) > 0,
49 RelocLength::from_u32((infos & 0x0600_0000) >> 25),
51 infos & 0x0800_0000 > 0,
53 ((infos & 0xF000_0000) >> 28) as u8,
55 )
56 } else {
57 (
58 (infos & 0xFFFF_FF00) >> 8,
60 infos & 0x0000_0080 > 0,
62 RelocLength::from_u32((infos & 0x0000_0060) >> 5),
64 infos & 0x0000_0010 > 0,
66 (infos & 0x0000_000F) as u8,
68 )
69 };
70
71 RelocationInfo {
72 r_address,
73 r_symbolnum,
74 r_pcrel,
75 r_length,
76 r_extern,
77 r_type,
78 }
79 }
80
81 #[cfg(target_endian = "little")]
86 pub fn write_into(self, write: &mut impl Write) {
87 write.write_i32_native(self.r_address);
88
89 let mut infos: u32 = 0;
90 infos |= self.r_symbolnum;
91 infos |= (self.r_pcrel as u32) * 0x0100_0000;
92 infos |= (self.r_length.to_u32()) << 25;
93 infos |= (self.r_extern as u32) * 0x0800_0000;
94 infos |= (self.r_type as u32) << 28;
95 write.write_u32_native(infos);
96 }
97
98 #[cfg(target_endian = "big")]
103 pub fn write_into(self, write: &mut impl Write) {
104 write.write_i32_native(self.r_address);
105
106 let mut infos: u32 = 0;
107 infos |= self.r_symbolnum << 8;
108 infos |= (self.r_pcrel as u32) * 0x0000_0080;
109 infos |= (self.r_length.to_u32()) << 5;
110 infos |= (self.r_extern as u32) * 0x0000_0010;
111 infos |= self.r_type as u32;
112 write.write_u32_native(infos);
113 }
114}
115
116#[derive(Debug, Clone, Copy, PartialEq, Eq, FromPrimitive)]
117pub enum RelocLength {
118 Byte = 0,
120 Word = 1,
122 Long = 2,
124 Quad = 3,
126}
127
128impl RelocLength {
129 pub fn to_u32(self) -> u32 {
130 self as u32
131 }
132
133 pub fn from_u32(n: u32) -> RelocLength {
134 FromPrimitive::from_u32(n).unwrap()
135 }
136}
137
138#[derive(Debug, Clone, Copy, PartialEq, Eq)]
139pub enum X86RelocType {
140 Vanilla = 0,
141 Pair = 1,
142 Sectdiff = 2,
143 PbLaPtr = 3,
144 LocalSectdiff = 4,
145 Tlv = 5,
146}
147
148impl X86RelocType {
149 pub fn to_u8(self) -> u8 {
150 self as u8
151 }
152
153 pub fn from_u8(n: u8) -> Self {
154 match n {
155 0 => X86RelocType::Vanilla,
156 1 => X86RelocType::Pair,
157 2 => X86RelocType::Sectdiff,
158 3 => X86RelocType::PbLaPtr,
159 4 => X86RelocType::LocalSectdiff,
160 5 => X86RelocType::Tlv,
161 _ => panic!("{} is not a valid x86 reloc type", n),
162 }
163 }
164}
165
166#[derive(Debug, Clone, Copy, PartialEq, Eq)]
167pub enum X86_64RelocType {
168 Unsigned = 0,
170 Signed = 1,
172 Branch = 2,
174 GotLoad = 3,
176 Got = 4,
178 Subtractor = 5,
180 Signed1 = 6,
182 Signed2 = 7,
184 Signed4 = 8,
186 Tlv = 9,
188}
189
190impl X86_64RelocType {
191 pub fn to_u8(self) -> u8 {
192 self as u8
193 }
194
195 pub fn from_u8(n: u8) -> Self {
196 match n {
197 0 => X86_64RelocType::Unsigned,
198 1 => X86_64RelocType::Signed,
199 2 => X86_64RelocType::Branch,
200 3 => X86_64RelocType::GotLoad,
201 4 => X86_64RelocType::Got,
202 5 => X86_64RelocType::Subtractor,
203 6 => X86_64RelocType::Signed1,
204 7 => X86_64RelocType::Signed2,
205 8 => X86_64RelocType::Signed4,
206 9 => X86_64RelocType::Tlv,
207 _ => panic!("{} is not a valid x86_64 reloc type", n),
208 }
209 }
210}
211
212#[cfg(test)]
213mod tests {
214 use super::*;
215
216 #[test]
217 fn write_and_read_relocation_info() {
218 let reloc = RelocationInfo {
219 r_address: 42,
220 r_symbolnum: 0x00323100,
221 r_pcrel: true,
222 r_length: RelocLength::Byte,
223 r_extern: false,
224 r_type: X86_64RelocType::Unsigned.to_u8(),
225 };
226
227 let mut buf = Vec::new();
228
229 reloc.write_into(&mut buf);
230
231 assert_eq!(buf.len(), RelocationInfo::SIZE as usize);
232
233 let read_reloc = RelocationInfo::read_from_in(&mut buf.as_slice(), Endian::NATIVE);
234
235 assert_eq!(read_reloc, reloc);
236 }
237}