1use byteorder::{ByteOrder, LittleEndian};
4
5use std::convert::TryFrom;
6
7#[derive(Debug)]
9pub struct ImpossibleRelocation { }
10
11
12pub trait Relocation {
16 type Encoding;
18 fn from_encoding(encoding: Self::Encoding) -> Self;
20 fn from_size(size: RelocationSize) -> Self;
22 fn size(&self) -> usize;
24 fn write_value(&self, buf: &mut [u8], value: isize) -> Result<(), ImpossibleRelocation>;
27 fn read_value(&self, buf: &[u8]) -> isize;
29 fn kind(&self) -> RelocationKind;
31 fn page_size() -> usize;
33}
34
35
36#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
38pub enum RelocationKind {
39 Relative = 0,
42 AbsToRel = 1,
46 RelToAbs = 2,
50}
51
52impl RelocationKind {
53 pub fn from_encoding(encoding: u8) -> Self {
55 match encoding {
56 0 => Self::Relative,
57 1 => Self::AbsToRel,
58 2 => Self::RelToAbs,
59 x => panic!("Unsupported relocation kind {}", x)
60 }
61 }
62}
63
64
65#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
69pub enum RelocationSize {
70 Byte = 1,
72 Word = 2,
74 DWord = 4,
76 QWord = 8,
78}
79
80impl Relocation for RelocationSize {
81 type Encoding = u8;
82 fn from_encoding(encoding: Self::Encoding) -> Self {
83 match encoding {
84 1 => RelocationSize::Byte,
85 2 => RelocationSize::Word,
86 4 => RelocationSize::DWord,
87 8 => RelocationSize::QWord,
88 x => panic!("Unsupported relocation size {}", x)
89 }
90 }
91 fn from_size(size: RelocationSize) -> Self {
92 size
93 }
94 fn size(&self) -> usize {
95 *self as usize
96 }
97 fn write_value(&self, buf: &mut [u8], value: isize) -> Result<(), ImpossibleRelocation> {
98 match self {
99 RelocationSize::Byte => buf[0] =
100 i8::try_from(value).map_err(|_| ImpossibleRelocation { } )?
101 as u8,
102 RelocationSize::Word => LittleEndian::write_i16(buf,
103 i16::try_from(value).map_err(|_| ImpossibleRelocation { } )?
104 ),
105 RelocationSize::DWord => LittleEndian::write_i32(buf,
106 i32::try_from(value).map_err(|_| ImpossibleRelocation { } )?
107 ),
108 RelocationSize::QWord => LittleEndian::write_i64(buf,
109 i64::try_from(value).map_err(|_| ImpossibleRelocation { } )?
110 ),
111 }
112 Ok(())
113 }
114 fn read_value(&self, buf: &[u8]) -> isize {
115 match self {
116 RelocationSize::Byte => buf[0] as i8 as isize,
117 RelocationSize::Word => LittleEndian::read_i16(buf) as isize,
118 RelocationSize::DWord => LittleEndian::read_i32(buf) as isize,
119 RelocationSize::QWord => LittleEndian::read_i64(buf) as isize,
120 }
121 }
122 fn kind(&self) -> RelocationKind {
123 RelocationKind::Relative
124 }
125 fn page_size() -> usize {
126 4096
127 }
128}
129
130pub(crate) fn fits_signed_bitfield(value: i64, bits: u8) -> bool {
131 if bits >= 64 {
132 return true;
133 }
134
135 let half = 1i64 << (bits - 1);
136 value < half && value >= -half
137}