From 872cf6d06f4d77637b4627fdc583bab79ee2372f Mon Sep 17 00:00:00 2001 From: johannst Date: Mon, 27 Feb 2023 22:52:40 +0000 Subject: deploy: 6486b862edc2750dba83848f62d6c9f3d4c6d3c2 --- src/juicebox_asm/imm.rs.html | 72 +++++ src/juicebox_asm/insn.rs.html | 94 ++++++ src/juicebox_asm/insn/add.rs.html | 28 ++ src/juicebox_asm/insn/dec.rs.html | 28 ++ src/juicebox_asm/insn/jmp.rs.html | 16 + src/juicebox_asm/insn/jnz.rs.html | 16 + src/juicebox_asm/insn/jz.rs.html | 16 + src/juicebox_asm/insn/mov.rs.html | 212 ++++++++++++ src/juicebox_asm/insn/ret.rs.html | 16 + src/juicebox_asm/insn/test.rs.html | 28 ++ src/juicebox_asm/label.rs.html | 146 +++++++++ src/juicebox_asm/lib.rs.html | 610 ++++++++++++++++++++++++++++++++++ src/juicebox_asm/prelude.rs.html | 18 ++ src/juicebox_asm/reg.rs.html | 648 +++++++++++++++++++++++++++++++++++++ src/juicebox_asm/rt.rs.html | 104 ++++++ 15 files changed, 2052 insertions(+) create mode 100644 src/juicebox_asm/imm.rs.html create mode 100644 src/juicebox_asm/insn.rs.html create mode 100644 src/juicebox_asm/insn/add.rs.html create mode 100644 src/juicebox_asm/insn/dec.rs.html create mode 100644 src/juicebox_asm/insn/jmp.rs.html create mode 100644 src/juicebox_asm/insn/jnz.rs.html create mode 100644 src/juicebox_asm/insn/jz.rs.html create mode 100644 src/juicebox_asm/insn/mov.rs.html create mode 100644 src/juicebox_asm/insn/ret.rs.html create mode 100644 src/juicebox_asm/insn/test.rs.html create mode 100644 src/juicebox_asm/label.rs.html create mode 100644 src/juicebox_asm/lib.rs.html create mode 100644 src/juicebox_asm/prelude.rs.html create mode 100644 src/juicebox_asm/reg.rs.html create mode 100644 src/juicebox_asm/rt.rs.html (limited to 'src') diff --git a/src/juicebox_asm/imm.rs.html b/src/juicebox_asm/imm.rs.html new file mode 100644 index 0000000..0990c92 --- /dev/null +++ b/src/juicebox_asm/imm.rs.html @@ -0,0 +1,72 @@ +imm.rs - source
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
+
/// Trait to interact with immediate operands.
+pub(crate) trait Imm {
+    /// Get immediate operand as slice of bytes.
+    fn bytes(&self) -> &[u8];
+}
+
+macro_rules! impl_imm {
+    ($name:ident, $size:expr, from: $( $from:ty ),* $(,)?) => {
+        /// Immediate operand.
+        pub struct $name([u8; $size]);
+
+        impl Imm for $name {
+            /// Get immediate operand as slice of bytes.
+            fn bytes(&self) -> &[u8] {
+                &self.0
+            }
+        }
+
+        $(
+        impl From<$from> for $name {
+            fn from(imm: $from) -> Self {
+                let mut buf = [0u8; $size];
+                let imm = imm.to_ne_bytes();
+                buf[0..imm.len()].copy_from_slice(&imm);
+                $name(buf)
+            }
+        }
+        )*
+    }
+}
+
+impl_imm!(Imm8, 1, from: u8, i8);
+impl_imm!(Imm16, 2, from: u16, i16, u8, i8);
+impl_imm!(Imm32, 4, from: u32, i32, u16, i16, u8, i8);
+impl_imm!(Imm64, 8, from: u64, i64, u32, i32, u16, i16, u8, i8);
+
+
\ No newline at end of file diff --git a/src/juicebox_asm/insn.rs.html b/src/juicebox_asm/insn.rs.html new file mode 100644 index 0000000..93134d8 --- /dev/null +++ b/src/juicebox_asm/insn.rs.html @@ -0,0 +1,94 @@ +insn.rs - source
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
+
mod add;
+mod dec;
+mod jmp;
+mod jnz;
+mod jz;
+mod mov;
+mod ret;
+mod test;
+
+pub trait Add<T, U> {
+    /// Emit an add instruction.
+    fn add(&mut self, op1: T, op2: U);
+}
+
+pub trait Dec<T> {
+    /// Emit a decrement instruction.
+    fn dec(&mut self, op1: T);
+}
+
+pub trait Jmp<T> {
+    /// Emit an unconditional jump instruction.
+    fn jmp(&mut self, op1: T);
+}
+
+pub trait Jnz<T> {
+    /// Emit a conditional jump if not zero instruction (`ZF = 0`).
+    fn jnz(&mut self, op1: T);
+}
+
+pub trait Jz<T> {
+    /// Emit a conditional jump if zero instruction (`ZF = 1`).
+    fn jz(&mut self, op1: T);
+}
+
+pub trait Mov<T, U> {
+    /// Emit an move instruction.
+    fn mov(&mut self, op1: T, op2: U);
+}
+
+pub trait Test<T, U> {
+    /// Emit a logical compare instruction.
+    ///
+    /// Computes the bit-wise logical AND of first operand and the second operand and sets the
+    /// `SF`, `ZF`, and `PF` status flags, the result is discarded.
+    fn test(&mut self, op1: T, op2: U);
+}
+
+
\ No newline at end of file diff --git a/src/juicebox_asm/insn/add.rs.html b/src/juicebox_asm/insn/add.rs.html new file mode 100644 index 0000000..eb5d35f --- /dev/null +++ b/src/juicebox_asm/insn/add.rs.html @@ -0,0 +1,28 @@ +add.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+
use crate::prelude::*;
+
+impl Add<Reg64, Reg64> for Asm {
+    fn add(&mut self, op1: Reg64, op2: Reg64) {
+        self.encode_rr(0x01, op1, op2);
+    }
+}
+
+impl Add<Reg32, Reg32> for Asm {
+    fn add(&mut self, op1: Reg32, op2: Reg32) {
+        self.encode_rr(0x01, op1, op2);
+    }
+}
+
+
\ No newline at end of file diff --git a/src/juicebox_asm/insn/dec.rs.html b/src/juicebox_asm/insn/dec.rs.html new file mode 100644 index 0000000..4cf1c5e --- /dev/null +++ b/src/juicebox_asm/insn/dec.rs.html @@ -0,0 +1,28 @@ +dec.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+
use crate::prelude::*;
+
+impl Dec<Reg64> for Asm {
+    fn dec(&mut self, op1: Reg64) {
+        self.encode_r(0xff, 1, op1);
+    }
+}
+
+impl Dec<Reg32> for Asm {
+    fn dec(&mut self, op1: Reg32) {
+        self.encode_r(0xff, 1, op1);
+    }
+}
+
+
\ No newline at end of file diff --git a/src/juicebox_asm/insn/jmp.rs.html b/src/juicebox_asm/insn/jmp.rs.html new file mode 100644 index 0000000..f3e4859 --- /dev/null +++ b/src/juicebox_asm/insn/jmp.rs.html @@ -0,0 +1,16 @@ +jmp.rs - source
1
+2
+3
+4
+5
+6
+7
+
use crate::prelude::*;
+
+impl Jmp<&mut Label> for Asm {
+    fn jmp(&mut self, op1: &mut Label) {
+        self.encode_jmp_label(&[0xe9], op1);
+    }
+}
+
+
\ No newline at end of file diff --git a/src/juicebox_asm/insn/jnz.rs.html b/src/juicebox_asm/insn/jnz.rs.html new file mode 100644 index 0000000..ac38297 --- /dev/null +++ b/src/juicebox_asm/insn/jnz.rs.html @@ -0,0 +1,16 @@ +jnz.rs - source
1
+2
+3
+4
+5
+6
+7
+
use crate::prelude::*;
+
+impl Jnz<&mut Label> for Asm {
+    fn jnz(&mut self, op1: &mut Label) {
+        self.encode_jmp_label(&[0x0f, 0x85], op1);
+    }
+}
+
+
\ No newline at end of file diff --git a/src/juicebox_asm/insn/jz.rs.html b/src/juicebox_asm/insn/jz.rs.html new file mode 100644 index 0000000..b6f16c1 --- /dev/null +++ b/src/juicebox_asm/insn/jz.rs.html @@ -0,0 +1,16 @@ +jz.rs - source
1
+2
+3
+4
+5
+6
+7
+
use crate::prelude::*;
+
+impl Jz<&mut Label> for Asm {
+    fn jz(&mut self, op1: &mut Label) {
+        self.encode_jmp_label(&[0x0f, 0x84], op1);
+    }
+}
+
+
\ No newline at end of file diff --git a/src/juicebox_asm/insn/mov.rs.html b/src/juicebox_asm/insn/mov.rs.html new file mode 100644 index 0000000..ebc9193 --- /dev/null +++ b/src/juicebox_asm/insn/mov.rs.html @@ -0,0 +1,212 @@ +mov.rs - source
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
+
use crate::prelude::*;
+
+// -- MOV : reg reg
+
+impl Mov<Reg64, Reg64> for Asm {
+    fn mov(&mut self, op1: Reg64, op2: Reg64) {
+        self.encode_rr(0x89, op1, op2);
+    }
+}
+
+impl Mov<Reg32, Reg32> for Asm {
+    fn mov(&mut self, op1: Reg32, op2: Reg32) {
+        self.encode_rr(0x89, op1, op2);
+    }
+}
+
+impl Mov<Reg16, Reg16> for Asm {
+    fn mov(&mut self, op1: Reg16, op2: Reg16) {
+        self.encode_rr(0x89, op1, op2);
+    }
+}
+
+impl Mov<Reg8, Reg8> for Asm {
+    fn mov(&mut self, op1: Reg8, op2: Reg8) {
+        self.encode_rr(0x88, op1, op2);
+    }
+}
+
+// -- MOV : mem reg
+
+impl Mov<MemOp, Reg64> for Asm {
+    fn mov(&mut self, op1: MemOp, op2: Reg64) {
+        self.encode_mr(0x89, op1, op2);
+    }
+}
+
+impl Mov<MemOp, Reg32> for Asm {
+    fn mov(&mut self, op1: MemOp, op2: Reg32) {
+        self.encode_mr(0x89, op1, op2);
+    }
+}
+
+impl Mov<MemOp, Reg16> for Asm {
+    fn mov(&mut self, op1: MemOp, op2: Reg16) {
+        self.encode_mr(0x89, op1, op2);
+    }
+}
+
+impl Mov<MemOp, Reg8> for Asm {
+    fn mov(&mut self, op1: MemOp, op2: Reg8) {
+        self.encode_mr(0x88, op1, op2);
+    }
+}
+
+// -- MOV : reg mem
+
+impl Mov<Reg64, MemOp> for Asm {
+    fn mov(&mut self, op1: Reg64, op2: MemOp) {
+        self.encode_rm(0x8b, op1, op2);
+    }
+}
+
+impl Mov<Reg32, MemOp> for Asm {
+    fn mov(&mut self, op1: Reg32, op2: MemOp) {
+        self.encode_rm(0x8b, op1, op2);
+    }
+}
+
+impl Mov<Reg16, MemOp> for Asm {
+    fn mov(&mut self, op1: Reg16, op2: MemOp) {
+        self.encode_rm(0x8b, op1, op2);
+    }
+}
+
+impl Mov<Reg8, MemOp> for Asm {
+    fn mov(&mut self, op1: Reg8, op2: MemOp) {
+        self.encode_rm(0x8a, op1, op2);
+    }
+}
+
+// -- MOV : reg imm
+
+impl Mov<Reg64, Imm64> for Asm {
+    fn mov(&mut self, op1: Reg64, op2: Imm64) {
+        self.encode_oi(0xb8, op1, op2);
+    }
+}
+
+impl Mov<Reg32, Imm32> for Asm {
+    fn mov(&mut self, op1: Reg32, op2: Imm32) {
+        self.encode_oi(0xb8, op1, op2);
+    }
+}
+
+impl Mov<Reg16, Imm16> for Asm {
+    fn mov(&mut self, op1: Reg16, op2: Imm16) {
+        self.encode_oi(0xb8, op1, op2);
+    }
+}
+
+impl Mov<Reg8, Imm8> for Asm {
+    fn mov(&mut self, op1: Reg8, op2: Imm8) {
+        self.encode_oi(0xb0, op1, op2);
+    }
+}
+
+
\ No newline at end of file diff --git a/src/juicebox_asm/insn/ret.rs.html b/src/juicebox_asm/insn/ret.rs.html new file mode 100644 index 0000000..a1ae96b --- /dev/null +++ b/src/juicebox_asm/insn/ret.rs.html @@ -0,0 +1,16 @@ +ret.rs - source
1
+2
+3
+4
+5
+6
+7
+
use crate::Asm;
+
+impl Asm {
+    pub fn ret(&mut self) {
+        self.emit(&[0xc3]);
+    }
+}
+
+
\ No newline at end of file diff --git a/src/juicebox_asm/insn/test.rs.html b/src/juicebox_asm/insn/test.rs.html new file mode 100644 index 0000000..e158f34 --- /dev/null +++ b/src/juicebox_asm/insn/test.rs.html @@ -0,0 +1,28 @@ +test.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+
use crate::prelude::*;
+
+impl Test<Reg64, Reg64> for Asm {
+    fn test(&mut self, op1: Reg64, op2: Reg64) {
+        self.encode_rr(0x85, op1, op2);
+    }
+}
+
+impl Test<Reg32, Reg32> for Asm {
+    fn test(&mut self, op1: Reg32, op2: Reg32) {
+        self.encode_rr(0x85, op1, op2);
+    }
+}
+
+
\ No newline at end of file diff --git a/src/juicebox_asm/label.rs.html b/src/juicebox_asm/label.rs.html new file mode 100644 index 0000000..cf7e7ae --- /dev/null +++ b/src/juicebox_asm/label.rs.html @@ -0,0 +1,146 @@ +label.rs - source
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
+
use std::collections::HashSet;
+
+/// A label which is used as target for jump instructions.
+///
+/// ```rust
+/// use juicebox_asm::prelude::*;
+///
+/// let mut lbl = Label::new();
+/// let mut asm = Asm::new();
+///
+/// // Skip the mov instruction.
+/// asm.jmp(&mut lbl);
+/// asm.mov(Reg64::rax, Reg64::rax);
+/// asm.bind(&mut lbl);
+/// ```
+///
+/// # Panics
+///
+/// Panics if the label is dropped while not yet bound, or having unresolved relocations.
+/// This is mainly a safety-guard to detect wrong usage.
+pub struct Label {
+    /// Location of the label. Will be set after the label is bound, else None.
+    location: Option<usize>,
+
+    /// Offsets that must be patched with the label location.
+    offsets: HashSet<usize>,
+}
+
+impl Label {
+    /// Create a new `unbound` [Label].
+    pub fn new() -> Label {
+        Label {
+            location: None,
+            offsets: HashSet::new(),
+        }
+    }
+
+    /// Bind the label to the `location`.
+    pub(crate) fn bind(&mut self, loc: usize) {
+        // A label can only be bound once!
+        assert!(!self.is_bound());
+
+        self.location = Some(loc);
+    }
+
+    /// Record an offset that must be patched with the label location.
+    pub(crate) fn record_offset(&mut self, off: usize) {
+        self.offsets.insert(off);
+    }
+
+    pub(crate) fn location(&self) -> Option<usize> {
+        self.location
+    }
+
+    pub(crate) fn offsets_mut(&mut self) -> &mut HashSet<usize> {
+        &mut self.offsets
+    }
+
+    /// Check whether the label is bound to a location.
+    const fn is_bound(&self) -> bool {
+        self.location.is_some()
+    }
+}
+
+impl Drop for Label {
+    fn drop(&mut self) {
+        // Ensure the label was bound when it is dropped.
+        assert!(self.is_bound());
+        // Ensure all offsets have been patched when the label is dropped.
+        assert!(self.offsets.is_empty());
+    }
+}
+
+
\ No newline at end of file diff --git a/src/juicebox_asm/lib.rs.html b/src/juicebox_asm/lib.rs.html new file mode 100644 index 0000000..7b17af1 --- /dev/null +++ b/src/juicebox_asm/lib.rs.html @@ -0,0 +1,610 @@ +lib.rs - source
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
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+
pub mod prelude;
+pub mod rt;
+
+mod imm;
+mod insn;
+mod label;
+mod reg;
+
+use imm::Imm;
+use label::Label;
+use reg::Reg;
+use reg::{Reg16, Reg32, Reg64, Reg8};
+
+pub enum MemOp {
+    Indirect(Reg64),
+    IndirectDisp(Reg64, i32),
+}
+
+impl MemOp {
+    const fn base(&self) -> Reg64 {
+        match self {
+            MemOp::Indirect(base) => *base,
+            MemOp::IndirectDisp(base, ..) => *base,
+        }
+    }
+}
+
+/// Encode the `REX` byte.
+const fn rex(w: bool, r: u8, x: u8, b: u8) -> u8 {
+    let w = if w { 1 } else { 0 };
+    let r = (r >> 3) & 1;
+    let x = (x >> 3) & 1;
+    let b = (b >> 3) & 1;
+    0b0100_0000 | ((w & 1) << 3) | (r << 2) | (x << 1) | b
+}
+
+/// Encode the `ModR/M` byte.
+const fn modrm(mod_: u8, reg: u8, rm: u8) -> u8 {
+    ((mod_ & 0b11) << 6) | ((reg & 0b111) << 3) | (rm & 0b111)
+}
+
+pub struct Asm {
+    buf: Vec<u8>,
+}
+
+impl Asm {
+    pub fn new() -> Asm {
+        let buf = Vec::with_capacity(1024);
+        Asm { buf }
+    }
+
+    pub fn into_code(self) -> Vec<u8> {
+        self.buf
+    }
+
+    fn emit(&mut self, bytes: &[u8]) {
+        self.buf.extend_from_slice(bytes);
+    }
+
+    fn emit_optional(&mut self, bytes: &[Option<u8>]) {
+        for byte in bytes.iter().filter_map(|&b| b) {
+            self.buf.push(byte);
+        }
+    }
+
+    fn emit_at(&mut self, pos: usize, bytes: &[u8]) {
+        if let Some(buf) = self.buf.get_mut(pos..pos + bytes.len()) {
+            buf.copy_from_slice(bytes);
+        } else {
+            unimplemented!();
+        }
+    }
+
+    /// Bind the [Label] to the current location.
+    pub fn bind(&mut self, label: &mut Label) {
+        // Bind the label to the current offset.
+        label.bind(self.buf.len());
+
+        // Resolve any pending relocations for the label.
+        self.resolve(label);
+    }
+
+    /// If the [Label] is bound, patch any pending relocation.
+    pub fn resolve(&mut self, label: &mut Label) {
+        if let Some(loc) = label.location() {
+            let loc = i32::try_from(loc).expect("Label location did not fit into i32.");
+
+            // Resolve any pending relocations for the label.
+            for off in label.offsets_mut().drain() {
+                // Displacement is relative to the next instruction following the jump.
+                // We record the offset to patch at the first byte of the disp32 therefore we need
+                // to account for that in the disp computation.
+                let disp32 = loc - i32::try_from(off).expect("Label offset did not fit into i32") - 4 /* account for the disp32 */;
+
+                // Patch the relocation with the disp32.
+                self.emit_at(off, &disp32.to_ne_bytes());
+            }
+        }
+    }
+
+    // -- Encode utilities.
+
+    fn encode_rr<T: Reg>(&mut self, opc: u8, op1: T, op2: T)
+    where
+        Self: EncodeRR<T>,
+    {
+        // MR operand encoding.
+        //   op1 -> modrm.rm
+        //   op2 -> modrm.reg
+        let modrm = modrm(
+            0b11,      /* mod */
+            op2.idx(), /* reg */
+            op1.idx(), /* rm */
+        );
+
+        let prefix = <Self as EncodeRR<T>>::legacy_prefix();
+        let rex = <Self as EncodeRR<T>>::rex(op1, op2);
+
+        self.emit_optional(&[prefix, rex]);
+        self.emit(&[opc, modrm]);
+    }
+
+    fn encode_oi<T: Reg, U: Imm>(&mut self, opc: u8, op1: T, op2: U)
+    where
+        Self: EncodeRI<T>,
+    {
+        let opc = opc + (op1.idx() & 0b111);
+        let prefix = <Self as EncodeRI<T>>::legacy_prefix();
+        let rex = <Self as EncodeRI<T>>::rex(op1);
+
+        self.emit_optional(&[prefix, rex]);
+        self.emit(&[opc]);
+        self.emit(op2.bytes());
+    }
+
+    fn encode_ri<T: Reg, U: Imm>(&mut self, opc: u8, opc_ext: u8, op1: T, op2: U)
+    where
+        Self: EncodeRI<T>,
+    {
+        // MI operand encoding.
+        //   op1           -> modrm.rm
+        //   opc extension -> modrm.reg
+        let modrm = modrm(
+            0b11,      /* mod */
+            opc_ext,   /* reg */
+            op1.idx(), /* rm */
+        );
+
+        let prefix = <Self as EncodeRI<T>>::legacy_prefix();
+        let rex = <Self as EncodeRI<T>>::rex(op1);
+
+        self.emit_optional(&[prefix, rex]);
+        self.emit(&[opc, modrm]);
+        self.emit(op2.bytes());
+    }
+
+    fn encode_r<T: Reg>(&mut self, opc: u8, opc_ext: u8, op1: T)
+    where
+        Self: EncodeRI<T>,
+    {
+        // M operand encoding.
+        //   op1           -> modrm.rm
+        //   opc extension -> modrm.reg
+        let modrm = modrm(
+            0b11,      /* mod */
+            opc_ext,   /* reg */
+            op1.idx(), /* rm */
+        );
+
+        let prefix = <Self as EncodeRI<T>>::legacy_prefix();
+        let rex = <Self as EncodeRI<T>>::rex(op1);
+
+        self.emit_optional(&[prefix, rex]);
+        self.emit(&[opc, modrm]);
+    }
+
+    fn encode_mr<T: Reg>(&mut self, opc: u8, op1: MemOp, op2: T)
+    where
+        Self: EncodeMR<T>,
+    {
+        // MR operand encoding.
+        //   op1 -> modrm.rm
+        //   op2 -> modrm.reg
+        let mode = match op1 {
+            MemOp::Indirect(..) => {
+                assert!(!op1.base().need_sib() && !op1.base().is_pc_rel());
+                0b00
+            }
+            MemOp::IndirectDisp(..) => {
+                assert!(!op1.base().need_sib());
+                0b10
+            }
+        };
+
+        let modrm = modrm(
+            mode,             /* mode */
+            op2.idx(),        /* reg */
+            op1.base().idx(), /* rm */
+        );
+        let prefix = <Self as EncodeMR<T>>::legacy_prefix();
+        let rex = <Self as EncodeMR<T>>::rex(&op1, op2);
+
+        self.emit_optional(&[prefix, rex]);
+        self.emit(&[opc, modrm]);
+        if let MemOp::IndirectDisp(_, disp) = op1 {
+            self.emit(&disp.to_ne_bytes());
+        }
+    }
+
+    fn encode_rm<T: Reg>(&mut self, opc: u8, op1: T, op2: MemOp)
+    where
+        Self: EncodeMR<T>,
+    {
+        // RM operand encoding.
+        //   op1 -> modrm.reg
+        //   op2 -> modrm.rm
+        self.encode_mr(opc, op2, op1);
+    }
+
+    fn encode_jmp_label(&mut self, opc: &[u8], op1: &mut Label) {
+        // Emit the opcode.
+        self.emit(opc);
+
+        // Record relocation offset starting at the first byte of the disp32.
+        op1.record_offset(self.buf.len());
+
+        // Emit a zeroed disp32, which serves as placeholder for the relocation.
+        self.emit(&[0u8; 4]);
+
+        // Resolve any pending relocations for the label.
+        self.resolve(op1);
+    }
+}
+
+// -- Encoder helper.
+
+trait EncodeRR<T: Reg> {
+    fn legacy_prefix() -> Option<u8> {
+        None
+    }
+
+    fn rex(op1: T, op2: T) -> Option<u8> {
+        if op1.need_rex() || op2.need_rex() {
+            Some(rex(op1.rexw(), op2.idx(), 0, op1.idx()))
+        } else {
+            None
+        }
+    }
+}
+
+impl EncodeRR<Reg8> for Asm {}
+impl EncodeRR<Reg32> for Asm {}
+impl EncodeRR<Reg16> for Asm {
+    fn legacy_prefix() -> Option<u8> {
+        Some(0x66)
+    }
+}
+impl EncodeRR<Reg64> for Asm {}
+
+trait EncodeRI<T: Reg> {
+    fn legacy_prefix() -> Option<u8> {
+        None
+    }
+
+    fn rex(op1: T) -> Option<u8> {
+        if op1.need_rex() {
+            Some(rex(op1.rexw(), 0, 0, op1.idx()))
+        } else {
+            None
+        }
+    }
+}
+
+impl EncodeRI<Reg8> for Asm {}
+impl EncodeRI<Reg32> for Asm {}
+impl EncodeRI<Reg16> for Asm {
+    fn legacy_prefix() -> Option<u8> {
+        Some(0x66)
+    }
+}
+impl EncodeRI<Reg64> for Asm {}
+
+trait EncodeMR<T: Reg> {
+    fn legacy_prefix() -> Option<u8> {
+        None
+    }
+
+    fn rex(op1: &MemOp, op2: T) -> Option<u8> {
+        if op2.need_rex() || (op1.base().is_ext()) {
+            Some(rex(op2.rexw(), op2.idx(), 0, op1.base().idx()))
+        } else {
+            None
+        }
+    }
+}
+
+impl EncodeMR<Reg8> for Asm {}
+impl EncodeMR<Reg16> for Asm {
+    fn legacy_prefix() -> Option<u8> {
+        Some(0x66)
+    }
+}
+impl EncodeMR<Reg32> for Asm {}
+impl EncodeMR<Reg64> for Asm {}
+
+
\ No newline at end of file diff --git a/src/juicebox_asm/prelude.rs.html b/src/juicebox_asm/prelude.rs.html new file mode 100644 index 0000000..51df87d --- /dev/null +++ b/src/juicebox_asm/prelude.rs.html @@ -0,0 +1,18 @@ +prelude.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+
pub use crate::Asm;
+pub use crate::MemOp;
+
+pub use crate::imm::{Imm16, Imm32, Imm64, Imm8};
+pub use crate::label::Label;
+pub use crate::reg::{Reg16, Reg32, Reg64, Reg8};
+
+pub use crate::insn::{Add, Dec, Jmp, Jnz, Jz, Mov, Test};
+
+
\ No newline at end of file diff --git a/src/juicebox_asm/reg.rs.html b/src/juicebox_asm/reg.rs.html new file mode 100644 index 0000000..65ff29e --- /dev/null +++ b/src/juicebox_asm/reg.rs.html @@ -0,0 +1,648 @@ +reg.rs - source
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
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+
/// Trait to interact with register operands.
+pub(crate) trait Reg {
+    /// Get the raw x64 register code.
+    fn idx(&self) -> u8;
+
+    /// Check if the registers needs the `REX.W` bit.
+    fn rexw(&self) -> bool;
+
+    /// Check if the register is an extended registers.
+    fn is_ext(&self) -> bool {
+        self.idx() > 7
+    }
+
+    /// Check if the register requires a `REX` byte.
+    fn need_rex(&self) -> bool {
+        self.is_ext() || self.rexw()
+    }
+
+    /// Check if the register requires a `SIB` byte if used as addressing operand.
+    ///
+    /// See [64 bit
+    /// addressing](https://wiki.osdev.org/X86-64_Instruction_Encoding#32.2F64-bit_addressing) for
+    /// further details.
+    fn need_sib(&self) -> bool {
+        self.idx() == 4 || self.idx() == 12
+    }
+
+    /// Check if the register is interpreted as `PC` relative if used as addressing operand.
+    ///
+    /// See [64 bit
+    /// addressing](https://wiki.osdev.org/X86-64_Instruction_Encoding#32.2F64-bit_addressing) for
+    /// further details.
+    fn is_pc_rel(&self) -> bool {
+        self.idx() == 5 || self.idx() == 13
+    }
+}
+
+macro_rules! impl_reg {
+    (ENUM_ONLY, $name:ident, { $($reg:ident),+ $(,)? }) => {
+        /// General purpose register operands.
+        #[allow(non_camel_case_types)]
+        #[derive(Copy, Clone)]
+        #[repr(u8)]
+        pub enum $name {
+            $( $reg, )+
+        }
+
+        #[cfg(test)]
+        impl $name {
+            fn iter() -> impl Iterator<Item = &'static $name> {
+                use $name::*;
+                [$( $reg, )+].iter()
+            }
+        }
+    };
+
+    ($name:ident, $rexw:expr, { $($reg:ident),+ $(,)? }) => {
+        impl_reg!(ENUM_ONLY, $name, { $( $reg, )+ });
+
+        impl Reg for $name {
+            /// Get the raw x64 register code.
+            fn idx(&self) -> u8 {
+                *self as u8
+            }
+
+            /// Check if the registers needs the `REX.W` bit.
+            fn rexw(&self) -> bool {
+                $rexw
+            }
+        }
+    }
+}
+
+impl_reg!(Reg64, true,  { rax, rcx, rdx, rbx, rsp, rbp, rsi, rdi, r8,  r9,  r10,  r11,  r12,  r13,  r14,  r15  });
+impl_reg!(Reg32, false, { eax, ecx, edx, ebx, esp, ebp, esi, edi, r8d, r9d, r10d, r11d, r12d, r13d, r14d, r15d });
+impl_reg!(Reg16, false, { ax,  cx,  dx,  bx,  sp,  bp,  si,  di,  r8w, r9w, r10w, r11w, r12w, r13w, r14w, r15w });
+impl_reg!(ENUM_ONLY,
+          Reg8,         { al,  cl,  dl,  bl,  spl, bpl, sil, dil, r8l, r9l, r10l, r11l, r12l, r13l, r14l, r15l,
+                          ah,  ch,  dh,  bh });
+
+impl Reg for Reg8 {
+    /// Get the raw x64 register code.
+    fn idx(&self) -> u8 {
+        match self {
+            Reg8::ah => 4,
+            Reg8::ch => 5,
+            Reg8::dh => 6,
+            Reg8::bh => 7,
+            _ => *self as u8,
+        }
+    }
+
+    /// Check if the registers needs the `REX.W` bit.
+    fn rexw(&self) -> bool {
+        false
+    }
+
+    /// Check whether the gp register needs a `REX` prefix
+    /// Check if the register requires a `REX` byte.
+    ///
+    /// For 1 byte addressing, register indexes `[4:7]` require a `REX` prefix, or else they will
+    /// be decoded as `{AH, CH, DH, BH}` accordingly.
+    ///
+    /// See [Registers](https://wiki.osdev.org/X86-64_Instruction_Encoding#Registers) for
+    /// further details or conduct `Table 3-1. Register Codes` in the *Intel Software Developers
+    /// Manual - Volume 2*.
+    fn need_rex(&self) -> bool {
+        self.idx() > 7 || matches!(self, Reg8::spl | Reg8::bpl | Reg8::sil | Reg8::dil)
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn test_reg8() {
+        use Reg8::*;
+
+        for r in Reg8::iter() {
+            // Check register index.
+            let idx = match r {
+                al => 0,
+                cl => 1,
+                dl => 2,
+                bl => 3,
+                spl => 4,
+                bpl => 5,
+                sil => 6,
+                dil => 7,
+                r8l => 8,
+                r9l => 9,
+                r10l => 10,
+                r11l => 11,
+                r12l => 12,
+                r13l => 13,
+                r14l => 14,
+                r15l => 15,
+                ah => 4,
+                ch => 5,
+                dh => 6,
+                bh => 7,
+            };
+            assert_eq!(r.idx(), idx);
+
+            // Check REX.W bit.
+            assert_eq!(r.rexw(), false);
+
+            // Check need REX byte.
+            let rex = match r {
+                r8l | r9l | r10l | r11l | r12l | r13l | r14l | r15l | spl | bpl | sil | dil => true,
+                _ => false,
+            };
+            assert_eq!(r.need_rex(), rex);
+
+            // Check need SIB byte.
+            let sib = match r {
+                spl | r12l | ah => true,
+                _ => false,
+            };
+            assert_eq!(r.need_sib(), sib);
+
+            // Check if is PC relative addressing.
+            let rel = match r {
+                bpl | r13l | ch => true,
+                _ => false,
+            };
+            assert_eq!(r.is_pc_rel(), rel);
+        }
+    }
+
+    #[test]
+    fn test_reg16() {
+        use Reg16::*;
+
+        for r in Reg16::iter() {
+            // Check register index.
+            let idx = match r {
+                ax => 0,
+                cx => 1,
+                dx => 2,
+                bx => 3,
+                sp => 4,
+                bp => 5,
+                si => 6,
+                di => 7,
+                r8w => 8,
+                r9w => 9,
+                r10w => 10,
+                r11w => 11,
+                r12w => 12,
+                r13w => 13,
+                r14w => 14,
+                r15w => 15,
+            };
+            assert_eq!(r.idx(), idx);
+
+            // Check REX.W bit.
+            assert_eq!(r.rexw(), false);
+
+            // Check need REX byte.
+            let rex = match r {
+                r8w | r9w | r10w | r11w | r12w | r13w | r14w | r15w => true,
+                _ => false,
+            };
+            assert_eq!(r.need_rex(), rex);
+
+            // Check need SIB byte.
+            let sib = match r {
+                sp | r12w => true,
+                _ => false,
+            };
+            assert_eq!(r.need_sib(), sib);
+
+            // Check if is PC relative addressing.
+            let rel = match r {
+                bp | r13w => true,
+                _ => false,
+            };
+            assert_eq!(r.is_pc_rel(), rel);
+        }
+    }
+
+    #[test]
+    fn test_reg32() {
+        use Reg32::*;
+
+        for r in Reg32::iter() {
+            // Check register index.
+            let idx = match r {
+                eax => 0,
+                ecx => 1,
+                edx => 2,
+                ebx => 3,
+                esp => 4,
+                ebp => 5,
+                esi => 6,
+                edi => 7,
+                r8d => 8,
+                r9d => 9,
+                r10d => 10,
+                r11d => 11,
+                r12d => 12,
+                r13d => 13,
+                r14d => 14,
+                r15d => 15,
+            };
+            assert_eq!(r.idx(), idx);
+
+            // Check REX.W bit.
+            assert_eq!(r.rexw(), false);
+
+            // Check need REX byte.
+            let rex = match r {
+                r8d | r9d | r10d | r11d | r12d | r13d | r14d | r15d => true,
+                _ => false,
+            };
+            assert_eq!(r.need_rex(), rex);
+
+            // Check need SIB byte.
+            let sib = match r {
+                esp | r12d => true,
+                _ => false,
+            };
+            assert_eq!(r.need_sib(), sib);
+
+            // Check if is PC relative addressing.
+            let rel = match r {
+                ebp | r13d => true,
+                _ => false,
+            };
+            assert_eq!(r.is_pc_rel(), rel);
+        }
+    }
+
+    #[test]
+    fn test_reg64() {
+        use Reg64::*;
+
+        for r in Reg64::iter() {
+            // Check register index.
+            let idx = match r {
+                rax => 0,
+                rcx => 1,
+                rdx => 2,
+                rbx => 3,
+                rsp => 4,
+                rbp => 5,
+                rsi => 6,
+                rdi => 7,
+                r8 => 8,
+                r9 => 9,
+                r10 => 10,
+                r11 => 11,
+                r12 => 12,
+                r13 => 13,
+                r14 => 14,
+                r15 => 15,
+            };
+            assert_eq!(r.idx(), idx);
+
+            // Check REX.W bit.
+            assert_eq!(r.rexw(), true);
+
+            // Check need REX byte.
+            assert_eq!(r.need_rex(), true);
+
+            // Check need SIB byte.
+            let sib = match r {
+                rsp | r12 => true,
+                _ => false,
+            };
+            assert_eq!(r.need_sib(), sib);
+
+            // Check if is PC relative addressing.
+            let rel = match r {
+                rbp | r13 => true,
+                _ => false,
+            };
+            assert_eq!(r.is_pc_rel(), rel);
+        }
+    }
+}
+
+
\ No newline at end of file diff --git a/src/juicebox_asm/rt.rs.html b/src/juicebox_asm/rt.rs.html new file mode 100644 index 0000000..a44e465 --- /dev/null +++ b/src/juicebox_asm/rt.rs.html @@ -0,0 +1,104 @@ +rt.rs - source
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
+
use core::ffi::c_void;
+use nix::sys::mman::{mmap, munmap, MapFlags, ProtFlags};
+
+/// A simple `mmap`ed runtime with executable pages.
+pub struct Runtime {
+    buf: *mut c_void,
+    len: usize,
+}
+
+impl Runtime {
+    /// Create a new [Runtime].
+    pub fn new(code: &[u8]) -> Runtime {
+        // Allocate a single page.
+        let len = core::num::NonZeroUsize::new(4096).unwrap();
+        let buf = unsafe {
+            mmap(
+                None,
+                len,
+                ProtFlags::PROT_WRITE | ProtFlags::PROT_READ | ProtFlags::PROT_EXEC,
+                MapFlags::MAP_PRIVATE | MapFlags::MAP_ANONYMOUS,
+                0, /* fd */
+                0, /* off */
+            )
+            .unwrap()
+        };
+        {
+            // Copy over code.
+            assert!(code.len() < len.get());
+            unsafe { std::ptr::copy_nonoverlapping(code.as_ptr(), buf.cast(), len.get()) };
+        }
+
+        Runtime {
+            buf,
+            len: len.get(),
+        }
+    }
+
+    /// Reinterpret the block of code as `F`.
+    #[inline]
+    pub unsafe fn as_fn<F>(&self) -> F {
+        unsafe { std::mem::transmute_copy(&self.buf) }
+    }
+}
+
+impl Drop for Runtime {
+    fn drop(&mut self) {
+        unsafe {
+            munmap(self.buf, self.len).expect("Failed to munmap Runtime");
+        }
+    }
+}
+
+
\ No newline at end of file -- cgit v1.2.3