1use byteorder::{ByteOrder, LittleEndian};
4use std::fmt::Debug;
5
6use std::convert::TryFrom;
7
8#[derive(Debug)]
10pub struct ImpossibleRelocation { }
11
12
13pub trait Relocation {
17 fn from_encoding(encoding: u8) -> Self;
19 fn from_size(kind: RelocationKind, size: RelocationSize) -> Self;
21 fn size(&self) -> usize;
23 fn write_value(&self, buf: &mut [u8], value: isize) -> Result<(), ImpossibleRelocation>;
26 fn read_value(&self, buf: &[u8]) -> isize;
28 fn kind(&self) -> RelocationKind;
30 fn page_size() -> usize;
32}
33
34pub trait ArchitectureRelocationEncoding : Clone + Copy + Debug {
37 fn decode(code: u8) -> Self;
39}
40
41
42#[derive(Clone, Copy, Debug)]
44pub enum RelocationKind {
45 Relative,
48 AbsToRel,
52 RelToAbs,
56 Absolute
59}
60
61#[derive(Clone, Copy, Debug)]
63pub enum RelocationEncoding<A: ArchitectureRelocationEncoding> {
64 Simple(RelocationSize),
66 ArchSpecific(A)
68}
69
70#[derive(Clone, Copy, Debug)]
73pub struct RelocationType<A: ArchitectureRelocationEncoding> {
74 pub kind: RelocationKind,
76 pub encoding: RelocationEncoding<A>
78}
79
80impl<A: ArchitectureRelocationEncoding> RelocationType<A> {
81 pub fn decode(code: u8) -> Self {
83 let kind = match code >> 6 {
84 0 => RelocationKind::Relative,
85 1 => RelocationKind::AbsToRel,
86 2 => RelocationKind::RelToAbs,
87 3 => RelocationKind::Absolute,
88 _ => unreachable!()
89 };
90
91 let encoding = match code & 0x3F {
92 0 => RelocationEncoding::Simple(RelocationSize::Byte),
93 1 => RelocationEncoding::Simple(RelocationSize::Word),
94 2 => RelocationEncoding::Simple(RelocationSize::DWord),
95 3 => RelocationEncoding::Simple(RelocationSize::QWord),
96 c => RelocationEncoding::ArchSpecific(A::decode(c - 4))
97 };
98 RelocationType {
99 kind,
100 encoding
101 }
102 }
103
104 pub fn from_size(kind: RelocationKind, size: RelocationSize) -> Self {
106 RelocationType {
107 kind,
108 encoding: RelocationEncoding::Simple(size)
109 }
110 }
111}
112
113#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
116pub enum RelocationSize {
117 Byte = 1,
119 Word = 2,
121 DWord = 4,
123 QWord = 8,
125}
126
127impl RelocationSize {
128 pub fn size(&self) -> usize {
130 *self as usize
131 }
132
133 pub fn write_value(&self, buf: &mut [u8], value: isize) -> Result<(), ImpossibleRelocation> {
135 match self {
136 RelocationSize::Byte => buf[0] =
137 i8::try_from(value).map_err(|_| ImpossibleRelocation { } )?
138 as u8,
139 RelocationSize::Word => LittleEndian::write_i16(buf,
140 i16::try_from(value).map_err(|_| ImpossibleRelocation { } )?
141 ),
142 RelocationSize::DWord => LittleEndian::write_i32(buf,
143 i32::try_from(value).map_err(|_| ImpossibleRelocation { } )?
144 ),
145 RelocationSize::QWord => LittleEndian::write_i64(buf,
146 i64::try_from(value).map_err(|_| ImpossibleRelocation { } )?
147 ),
148 }
149 Ok(())
150 }
151
152 pub fn read_value(&self, buf: &[u8]) -> isize {
154 match self {
155 RelocationSize::Byte => buf[0] as i8 as isize,
156 RelocationSize::Word => LittleEndian::read_i16(buf) as isize,
157 RelocationSize::DWord => LittleEndian::read_i32(buf) as isize,
158 RelocationSize::QWord => LittleEndian::read_i64(buf) as isize,
159 }
160 }
161}
162
163#[derive(Copy, Clone, Debug)]
164enum NoComplexRelocationEncodings {}
165
166impl ArchitectureRelocationEncoding for NoComplexRelocationEncodings {
167 fn decode(code: u8) -> Self {
168 panic!("Invalid complex relocation code {code} given for the current architecture");
169 }
170}
171
172#[derive(Debug, Clone, Copy)]
174pub struct SimpleRelocation(RelocationType<NoComplexRelocationEncodings>);
175
176impl Relocation for SimpleRelocation {
178 fn from_encoding(encoding: u8) -> Self {
179 SimpleRelocation(RelocationType::decode(encoding))
180 }
181
182 fn from_size(kind: RelocationKind, size: RelocationSize) -> Self {
183 SimpleRelocation(RelocationType::from_size(kind, size))
184 }
185
186 fn size(&self) -> usize {
187 match self.0.encoding {
188 RelocationEncoding::Simple(s) => s.size(),
189 _ => unreachable!()
190 }
191 }
192
193 fn write_value(&self, buf: &mut [u8], value: isize) -> Result<(), ImpossibleRelocation> {
194 match self.0.encoding {
195 RelocationEncoding::Simple(s) => s.write_value(buf, value),
196 _ => unreachable!()
197 }
198 }
199
200 fn read_value(&self, buf: &[u8]) -> isize {
201 match self.0.encoding {
202 RelocationEncoding::Simple(s) => s.read_value(buf),
203 _ => unreachable!()
204 }
205 }
206
207 fn kind(&self) -> RelocationKind {
208 self.0.kind
209 }
210
211 fn page_size() -> usize {
212 4096
213 }
214}
215
216pub(crate) fn fits_signed_bitfield(value: i64, bits: u8) -> bool {
217 if bits >= 64 {
218 return true;
219 }
220
221 let half = 1i64 << (bits - 1);
222 value < half && value >= -half
223}