Coverage Report

Created: 2024-10-16 07:58

/rust/registry/src/index.crates.io-6f17d22bba15001f/dynasmrt-1.2.3/src/relocations.rs
Line
Count
Source (jump to first uncovered line)
1
//! This module defines the `Relocation` trait and several utilities for implementing relocations.
2
3
use byteorder::{ByteOrder, LittleEndian};
4
5
use std::convert::TryFrom;
6
7
/// Error returned when encoding a relocation failed
8
#[derive(Debug)]
9
pub struct ImpossibleRelocation { }
10
11
12
/// Used to inform assemblers on how to implement relocations for each architecture.
13
/// When implementing a new architecture, one simply has to implement this trait for
14
/// the architecture's relocation definition.
15
pub trait Relocation {
16
    /// The encoded representation for this relocation that is emitted by the dynasm! macro.
17
    type Encoding;
18
    /// construct this relocation from an encoded representation.
19
    fn from_encoding(encoding: Self::Encoding) -> Self;
20
    /// construct this relocation from a simple size. This is used to implement relocations in directives and literal pools.
21
    fn from_size(size: RelocationSize) -> Self;
22
    /// The size of the slice of bytes affected by this relocation
23
    fn size(&self) -> usize;
24
    /// Write a value into a buffer of size `self.size()` in the format of this relocation.
25
    /// Any bits not part of the relocation should be preserved.
26
    fn write_value(&self, buf: &mut [u8], value: isize) -> Result<(), ImpossibleRelocation>;
27
    /// Read a value from a buffer of size `self.size()` in the format of this relocation.
28
    fn read_value(&self, buf: &[u8]) -> isize;
29
    /// Specifies what kind of relocation this relocation instance is.
30
    fn kind(&self) -> RelocationKind;
31
    /// Specifies the default page size on this platform.
32
    fn page_size() -> usize;
33
}
34
35
36
/// Specifies what kind of relocation a relocation is.
37
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
38
pub enum RelocationKind {
39
    /// A simple, PC-relative relocation. These can be encoded once and do not need
40
    /// to be adjusted when the executable buffer is moved.
41
    Relative = 0,
42
    /// An absolute relocation to a relative address,
43
    /// i.e. trying to put the address of a dynasm x86 function in a register
44
    /// This means adjustment is necessary when the executable buffer is moved
45
    AbsToRel = 1,
46
    /// A relative relocation to an absolute address,
47
    /// i.e. trying to call a rust function with a dynasm x86 call.
48
    /// This means adjustment is necessary when the executable buffer is moved
49
    RelToAbs = 2,
50
}
51
52
impl RelocationKind {
53
    /// Converts back from numeric value to RelocationKind
54
0
    pub fn from_encoding(encoding: u8) -> Self {
55
0
        match encoding {
56
0
            0 => Self::Relative,
57
0
            1 => Self::AbsToRel,
58
0
            2 => Self::RelToAbs,
59
0
            x => panic!("Unsupported relocation kind {}", x)
60
        }
61
0
    }
Unexecuted instantiation: <dynasmrt::relocations::RelocationKind>::from_encoding
Unexecuted instantiation: <dynasmrt::relocations::RelocationKind>::from_encoding
62
}
63
64
65
/// A descriptor for the size of a relocation. This also doubles as a relocation itself
66
/// for relocations in data directives. Can be converted to relocations of any kind of architecture
67
/// using `Relocation::from_size`.
68
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
69
pub enum RelocationSize {
70
    /// A byte-sized relocation
71
    Byte = 1,
72
    /// A two-byte relocation
73
    Word = 2,
74
    /// A four-byte sized relocation
75
    DWord = 4,
76
    /// An 8-byte sized relocation
77
    QWord = 8,
78
}
79
80
impl Relocation for RelocationSize {
81
    type Encoding = u8;
82
2.27M
    fn from_encoding(encoding: Self::Encoding) -> Self {
83
2.27M
        match encoding {
84
0
            1 => RelocationSize::Byte,
85
0
            2 => RelocationSize::Word,
86
2.27M
            4 => RelocationSize::DWord,
87
0
            8 => RelocationSize::QWord,
88
0
            x => panic!("Unsupported relocation size {}", x)
89
        }
90
2.27M
    }
<dynasmrt::relocations::RelocationSize as dynasmrt::relocations::Relocation>::from_encoding
Line
Count
Source
82
1.88M
    fn from_encoding(encoding: Self::Encoding) -> Self {
83
1.88M
        match encoding {
84
0
            1 => RelocationSize::Byte,
85
0
            2 => RelocationSize::Word,
86
1.88M
            4 => RelocationSize::DWord,
87
0
            8 => RelocationSize::QWord,
88
0
            x => panic!("Unsupported relocation size {}", x)
89
        }
90
1.88M
    }
<dynasmrt::relocations::RelocationSize as dynasmrt::relocations::Relocation>::from_encoding
Line
Count
Source
82
383k
    fn from_encoding(encoding: Self::Encoding) -> Self {
83
383k
        match encoding {
84
0
            1 => RelocationSize::Byte,
85
0
            2 => RelocationSize::Word,
86
383k
            4 => RelocationSize::DWord,
87
0
            8 => RelocationSize::QWord,
88
0
            x => panic!("Unsupported relocation size {}", x)
89
        }
90
383k
    }
91
0
    fn from_size(size: RelocationSize) -> Self {
92
0
        size
93
0
    }
Unexecuted instantiation: <dynasmrt::relocations::RelocationSize as dynasmrt::relocations::Relocation>::from_size
Unexecuted instantiation: <dynasmrt::relocations::RelocationSize as dynasmrt::relocations::Relocation>::from_size
94
2.27M
    fn size(&self) -> usize {
95
2.27M
        *self as usize
96
2.27M
    }
<dynasmrt::relocations::RelocationSize as dynasmrt::relocations::Relocation>::size
Line
Count
Source
94
1.88M
    fn size(&self) -> usize {
95
1.88M
        *self as usize
96
1.88M
    }
Unexecuted instantiation: <dynasmrt::relocations::RelocationSize as dynasmrt::relocations::Relocation>::size
<dynasmrt::relocations::RelocationSize as dynasmrt::relocations::Relocation>::size
Line
Count
Source
94
383k
    fn size(&self) -> usize {
95
383k
        *self as usize
96
383k
    }
Unexecuted instantiation: <dynasmrt::relocations::RelocationSize as dynasmrt::relocations::Relocation>::size
97
2.27M
    fn write_value(&self, buf: &mut [u8], value: isize) -> Result<(), ImpossibleRelocation> {
98
2.27M
        match self {
99
0
            RelocationSize::Byte => buf[0] =
100
0
                i8::try_from(value).map_err(|_| ImpossibleRelocation { } )?
Unexecuted instantiation: <dynasmrt::relocations::RelocationSize as dynasmrt::relocations::Relocation>::write_value::{closure#0}
Unexecuted instantiation: <dynasmrt::relocations::RelocationSize as dynasmrt::relocations::Relocation>::write_value::{closure#0}
101
            as u8,
102
0
            RelocationSize::Word => LittleEndian::write_i16(buf,
103
0
                i16::try_from(value).map_err(|_| ImpossibleRelocation { } )?
Unexecuted instantiation: <dynasmrt::relocations::RelocationSize as dynasmrt::relocations::Relocation>::write_value::{closure#1}
Unexecuted instantiation: <dynasmrt::relocations::RelocationSize as dynasmrt::relocations::Relocation>::write_value::{closure#1}
104
            ),
105
2.27M
            RelocationSize::DWord => LittleEndian::write_i32(buf,
106
2.27M
                i32::try_from(value).map_err(|_| ImpossibleRelocation { } )?
Unexecuted instantiation: <dynasmrt::relocations::RelocationSize as dynasmrt::relocations::Relocation>::write_value::{closure#2}
Unexecuted instantiation: <dynasmrt::relocations::RelocationSize as dynasmrt::relocations::Relocation>::write_value::{closure#2}
107
            ),
108
0
            RelocationSize::QWord => LittleEndian::write_i64(buf,
109
0
                i64::try_from(value).map_err(|_| ImpossibleRelocation { } )?
Unexecuted instantiation: <dynasmrt::relocations::RelocationSize as dynasmrt::relocations::Relocation>::write_value::{closure#3}
Unexecuted instantiation: <dynasmrt::relocations::RelocationSize as dynasmrt::relocations::Relocation>::write_value::{closure#3}
110
            ),
111
        }
112
2.27M
        Ok(())
113
2.27M
    }
<dynasmrt::relocations::RelocationSize as dynasmrt::relocations::Relocation>::write_value
Line
Count
Source
97
1.88M
    fn write_value(&self, buf: &mut [u8], value: isize) -> Result<(), ImpossibleRelocation> {
98
1.88M
        match self {
99
0
            RelocationSize::Byte => buf[0] =
100
0
                i8::try_from(value).map_err(|_| ImpossibleRelocation { } )?
101
            as u8,
102
0
            RelocationSize::Word => LittleEndian::write_i16(buf,
103
0
                i16::try_from(value).map_err(|_| ImpossibleRelocation { } )?
104
            ),
105
1.88M
            RelocationSize::DWord => LittleEndian::write_i32(buf,
106
1.88M
                i32::try_from(value).map_err(|_| ImpossibleRelocation { } )?
107
            ),
108
0
            RelocationSize::QWord => LittleEndian::write_i64(buf,
109
0
                i64::try_from(value).map_err(|_| ImpossibleRelocation { } )?
110
            ),
111
        }
112
1.88M
        Ok(())
113
1.88M
    }
<dynasmrt::relocations::RelocationSize as dynasmrt::relocations::Relocation>::write_value
Line
Count
Source
97
383k
    fn write_value(&self, buf: &mut [u8], value: isize) -> Result<(), ImpossibleRelocation> {
98
383k
        match self {
99
0
            RelocationSize::Byte => buf[0] =
100
0
                i8::try_from(value).map_err(|_| ImpossibleRelocation { } )?
101
            as u8,
102
0
            RelocationSize::Word => LittleEndian::write_i16(buf,
103
0
                i16::try_from(value).map_err(|_| ImpossibleRelocation { } )?
104
            ),
105
383k
            RelocationSize::DWord => LittleEndian::write_i32(buf,
106
383k
                i32::try_from(value).map_err(|_| ImpossibleRelocation { } )?
107
            ),
108
0
            RelocationSize::QWord => LittleEndian::write_i64(buf,
109
0
                i64::try_from(value).map_err(|_| ImpossibleRelocation { } )?
110
            ),
111
        }
112
383k
        Ok(())
113
383k
    }
114
0
    fn read_value(&self, buf: &[u8]) -> isize {
115
0
        match self {
116
0
            RelocationSize::Byte => buf[0] as i8 as isize,
117
0
            RelocationSize::Word => LittleEndian::read_i16(buf) as isize,
118
0
            RelocationSize::DWord => LittleEndian::read_i32(buf) as isize,
119
0
            RelocationSize::QWord => LittleEndian::read_i64(buf) as isize,
120
        }
121
0
    }
Unexecuted instantiation: <dynasmrt::relocations::RelocationSize as dynasmrt::relocations::Relocation>::read_value
Unexecuted instantiation: <dynasmrt::relocations::RelocationSize as dynasmrt::relocations::Relocation>::read_value
122
0
    fn kind(&self) -> RelocationKind {
123
0
        RelocationKind::Relative
124
0
    }
Unexecuted instantiation: <dynasmrt::relocations::RelocationSize as dynasmrt::relocations::Relocation>::kind
Unexecuted instantiation: <dynasmrt::relocations::RelocationSize as dynasmrt::relocations::Relocation>::kind
125
0
    fn page_size() -> usize {
126
0
        4096
127
0
    }
Unexecuted instantiation: <dynasmrt::relocations::RelocationSize as dynasmrt::relocations::Relocation>::page_size
Unexecuted instantiation: <dynasmrt::relocations::RelocationSize as dynasmrt::relocations::Relocation>::page_size
128
}
129
130
0
pub(crate) fn fits_signed_bitfield(value: i64, bits: u8) -> bool {
131
0
    if bits >= 64 {
132
0
        return true;
133
0
    }
134
0
135
0
    let half = 1i64 << (bits - 1);
136
0
    value < half && value >= -half
137
0
}
Unexecuted instantiation: dynasmrt::relocations::fits_signed_bitfield
Unexecuted instantiation: dynasmrt::relocations::fits_signed_bitfield