cranelift_assembler_x64/
api.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
//! Contains traits that a user of this assembler must implement.

use crate::reg;
use crate::xmm;
use std::{num::NonZeroU8, ops::Index, vec::Vec};

/// Describe how an instruction is emitted into a code buffer.
pub trait CodeSink {
    /// Add 1 byte to the code section.
    fn put1(&mut self, _: u8);

    /// Add 2 bytes to the code section.
    fn put2(&mut self, _: u16);

    /// Add 4 bytes to the code section.
    fn put4(&mut self, _: u32);

    /// Add 8 bytes to the code section.
    fn put8(&mut self, _: u64);

    /// Inform the code buffer of a possible trap at the current location;
    /// required for assembling memory accesses.
    fn add_trap(&mut self, code: TrapCode);

    /// Return the byte offset of the current location in the code buffer;
    /// required for assembling RIP-relative memory accesses.
    fn current_offset(&self) -> u32;

    /// Inform the code buffer of a use of `label` at `offset`; required for
    /// assembling RIP-relative memory accesses.
    fn use_label_at_offset(&mut self, offset: u32, label: Label);

    /// Return the label for a constant `id`; required for assembling
    /// RIP-relative memory accesses of constants.
    fn get_label_for_constant(&mut self, id: Constant) -> Label;
}

/// Provide a convenient implementation for testing.
impl CodeSink for Vec<u8> {
    fn put1(&mut self, v: u8) {
        self.extend_from_slice(&[v]);
    }

    fn put2(&mut self, v: u16) {
        self.extend_from_slice(&v.to_le_bytes());
    }

    fn put4(&mut self, v: u32) {
        self.extend_from_slice(&v.to_le_bytes());
    }

    fn put8(&mut self, v: u64) {
        self.extend_from_slice(&v.to_le_bytes());
    }

    fn add_trap(&mut self, _: TrapCode) {}

    fn current_offset(&self) -> u32 {
        self.len().try_into().unwrap()
    }

    fn use_label_at_offset(&mut self, _: u32, _: Label) {}

    fn get_label_for_constant(&mut self, c: Constant) -> Label {
        Label(c.0)
    }
}

/// Wrap [`CodeSink`]-specific labels.
#[derive(Debug, Clone)]
#[cfg_attr(any(test, feature = "fuzz"), derive(arbitrary::Arbitrary))]
pub struct Label(pub u32);

/// Wrap [`CodeSink`]-specific constant keys.
#[derive(Debug, Clone)]
#[cfg_attr(any(test, feature = "fuzz"), derive(arbitrary::Arbitrary))]
pub struct Constant(pub u32);

/// Wrap [`CodeSink`]-specific trap codes.
#[derive(Debug, Clone, Copy)]
#[cfg_attr(any(test, feature = "fuzz"), derive(arbitrary::Arbitrary))]
pub struct TrapCode(pub NonZeroU8);

/// A table mapping `KnownOffset` identifiers to their `i32` offset values.
///
/// When encoding instructions, Cranelift may not know all of the information
/// needed to construct an immediate. Specifically, addressing modes that
/// require knowing the size of the tail arguments or outgoing arguments (see
/// `SyntheticAmode::finalize`) will not know these sizes until emission.
///
/// This table allows up to do a "late" look up of these values by their
/// `KnownOffset`.
pub trait KnownOffsetTable: Index<KnownOffset, Output = i32> {}
impl KnownOffsetTable for Vec<i32> {}
/// Provide a convenient implementation for testing.
impl KnownOffsetTable for [i32; 2] {}

/// A `KnownOffset` is a unique identifier for a specific offset known only at
/// emission time.
pub type KnownOffset = usize;

/// A type set fixing the register types used in the assembler.
///
/// This assembler is parameterizable over register types; this allows the
/// assembler users (e.g., Cranelift) to define their own register types
/// independent of this crate.
pub trait Registers {
    /// An x64 general purpose register that may be read.
    type ReadGpr: AsReg;

    /// An x64 general purpose register that may be read and written.
    type ReadWriteGpr: AsReg;

    /// An x64 SSE register that may be read.
    type ReadXmm: AsReg;

    /// An x64 SSE register that may be read and written.
    type ReadWriteXmm: AsReg;
}

/// Describe how to interact with an external register type.
pub trait AsReg: Clone + std::fmt::Debug {
    /// Create a register from its hardware encoding.
    ///
    /// This is primarily useful for fuzzing, though it is also useful for
    /// generating fixed registers.
    fn new(enc: u8) -> Self;

    /// Return the register's hardware encoding; e.g., `0` for `%rax`.
    fn enc(&self) -> u8;

    /// Return the register name.
    fn to_string(&self, size: Option<reg::Size>) -> &str {
        match size {
            Some(size) => reg::enc::to_string(self.enc(), size),
            None => xmm::enc::to_string(self.enc()),
        }
    }
}

/// Provide a convenient implementation for testing.
impl AsReg for u8 {
    fn new(enc: u8) -> Self {
        enc
    }
    fn enc(&self) -> u8 {
        *self
    }
}

/// Describe a visitor for the register operands of an instruction.
///
/// Due to how Cranelift's register allocation works, we allow the visitor to
/// modify the register operands in place. This allows Cranelift to convert
/// virtual registers (`[128..N)`) to physical registers (`[0..16)`) without
/// re-allocating the entire instruction object.
pub trait RegisterVisitor<R: Registers> {
    /// Visit a read-only register.
    fn read(&mut self, reg: &mut R::ReadGpr);
    /// Visit a read-write register.
    fn read_write(&mut self, reg: &mut R::ReadWriteGpr);
    /// Visit a read-only fixed register; for safety, this register cannot be
    /// modified in-place.
    fn fixed_read(&mut self, reg: &R::ReadGpr);
    /// Visit a read-write fixed register; for safety, this register cannot be
    /// modified in-place.
    fn fixed_read_write(&mut self, reg: &R::ReadWriteGpr);
    /// Visit a read-only SSE register.
    fn read_xmm(&mut self, reg: &mut R::ReadXmm);
    /// Visit a read-write SSE register.
    fn read_write_xmm(&mut self, reg: &mut R::ReadWriteXmm);
    /// Visit a read-only fixed SSE register; for safety, this register cannot
    /// be modified in-place.
    fn fixed_read_xmm(&mut self, reg: &R::ReadXmm);
    /// Visit a read-write fixed SSE register; for safety, this register cannot
    /// be modified in-place.
    fn fixed_read_write_xmm(&mut self, reg: &R::ReadWriteXmm);
}