From 5289cbf5331dfd0d0c2242a7e7c8030aa4032c7e Mon Sep 17 00:00:00 2001 From: johannst Date: Sat, 7 Dec 2024 01:01:45 +0000 Subject: deploy: 9c3c3fd923d894d2351eb22129ea693eb98fa8ff --- src/juicebox_asm/asm.rs.html | 281 ++++++++++++++++++++++++++++++++++++++----- 1 file changed, 254 insertions(+), 27 deletions(-) (limited to 'src/juicebox_asm/asm.rs.html') diff --git a/src/juicebox_asm/asm.rs.html b/src/juicebox_asm/asm.rs.html index 4418397..3f24ae2 100644 --- a/src/juicebox_asm/asm.rs.html +++ b/src/juicebox_asm/asm.rs.html @@ -1,5 +1,5 @@ -asm.rs - source -
1
+asm.rs - source

juicebox_asm/
asm.rs

+1
 2
 3
 4
@@ -344,7 +344,120 @@
 343
 344
 345
-
//! The `x64` jit assembler.
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
//! The `x64` jit assembler.
 
 use crate::*;
 use imm::Imm;
@@ -364,6 +477,11 @@
     ((mod_ & 0b11) << 6) | ((reg & 0b111) << 3) | (rm & 0b111)
 }
 
+/// Encode the `SIB` byte.
+const fn sib(scale: u8, index: u8, base: u8) -> u8 {
+    ((scale & 0b11) << 6) | ((index & 0b111) << 3) | (base & 0b111)
+}
+
 /// `x64` jit assembler.
 pub struct Asm {
     buf: Vec<u8>,
@@ -495,6 +613,52 @@
         self.emit(&[opc, modrm]);
     }
 
+    /// Encode a memory operand instruction.
+    pub(crate) fn encode_m<T: MemOpSized>(&mut self, opc: u8, opc_ext: u8, op1: T)
+    where
+        Self: EncodeM<T>,
+    {
+        let op1 = op1.mem_op();
+
+        // M operand encoding.
+        //   op1 -> modrm.rm
+        let (mode, rm) = match op1 {
+            MemOp::Indirect(..) => {
+                assert!(!op1.base().need_sib() && !op1.base().is_pc_rel());
+                (0b00, op1.base().idx())
+            }
+            MemOp::IndirectDisp(..) => {
+                assert!(!op1.base().need_sib());
+                (0b10, op1.base().idx())
+            }
+            MemOp::IndirectBaseIndex(..) => {
+                assert!(!op1.base().is_pc_rel());
+                // Using rsp as index register is interpreted as just base w/o offset.
+                //   https://wiki.osdev.org/X86-64_Instruction_Encoding#32.2F64-bit_addressing_2
+                // Disallow this case, as guard for the user.
+                assert!(!matches!(op1.index(), Reg64::rsp));
+                (0b00, 0b100)
+            }
+        };
+
+        let modrm = modrm(
+            mode,    /* mode */
+            opc_ext, /* reg */
+            rm,      /* rm */
+        );
+
+        let prefix = <Self as EncodeM<T>>::legacy_prefix();
+        let rex = <Self as EncodeM<T>>::rex(&op1);
+
+        self.emit_optional(&[prefix, rex]);
+        self.emit(&[opc, modrm]);
+        match op1 {
+            MemOp::Indirect(..) => {}
+            MemOp::IndirectDisp(_, disp) => self.emit(&disp.to_ne_bytes()),
+            MemOp::IndirectBaseIndex(base, index) => self.emit(&[sib(0, index.idx(), base.idx())]),
+        }
+    }
+
     /// Encode a memory-immediate instruction.
     pub(crate) fn encode_mi<T: Imm>(&mut self, opc: u8, opc_ext: u8, op1: MemOp, op2: T)
     where
@@ -503,21 +667,29 @@
         // MI operand encoding.
         //   op1 -> modrm.rm
         //   op2 -> imm
-        let mode = match op1 {
+        let (mode, rm) = match op1 {
             MemOp::Indirect(..) => {
                 assert!(!op1.base().need_sib() && !op1.base().is_pc_rel());
-                0b00
-            }
+                (0b00, op1.base().idx())
+            }
             MemOp::IndirectDisp(..) => {
                 assert!(!op1.base().need_sib());
-                0b10
-            }
+                (0b10, op1.base().idx())
+            }
+            MemOp::IndirectBaseIndex(..) => {
+                assert!(!op1.base().is_pc_rel());
+                // Using rsp as index register is interpreted as just base w/o offset.
+                //   https://wiki.osdev.org/X86-64_Instruction_Encoding#32.2F64-bit_addressing_2
+                // Disallow this case, as guard for the user.
+                assert!(!matches!(op1.index(), Reg64::rsp));
+                (0b00, 0b100)
+            }
         };
 
         let modrm = modrm(
-            mode,             /* mode */
-            opc_ext,          /* reg */
-            op1.base().idx(), /* rm */
+            mode,    /* mode */
+            opc_ext, /* reg */
+            rm,      /* rm */
         );
 
         let prefix = <Self as EncodeMI<T>>::legacy_prefix();
@@ -525,8 +697,10 @@
 
         self.emit_optional(&[prefix, rex]);
         self.emit(&[opc, modrm]);
-        if let MemOp::IndirectDisp(_, disp) = op1 {
-            self.emit(&disp.to_ne_bytes());
+        match op1 {
+            MemOp::Indirect(..) => {}
+            MemOp::IndirectDisp(_, disp) => self.emit(&disp.to_ne_bytes()),
+            MemOp::IndirectBaseIndex(base, index) => self.emit(&[sib(0, index.idx(), base.idx())]),
         }
         self.emit(op2.bytes());
     }
@@ -539,29 +713,40 @@
         // MR operand encoding.
         //   op1 -> modrm.rm
         //   op2 -> modrm.reg
-        let mode = match op1 {
+        let (mode, rm) = match op1 {
             MemOp::Indirect(..) => {
                 assert!(!op1.base().need_sib() && !op1.base().is_pc_rel());
-                0b00
-            }
+                (0b00, op1.base().idx())
+            }
             MemOp::IndirectDisp(..) => {
                 assert!(!op1.base().need_sib());
-                0b10
-            }
+                (0b10, op1.base().idx())
+            }
+            MemOp::IndirectBaseIndex(..) => {
+                assert!(!op1.base().is_pc_rel());
+                // Using rsp as index register is interpreted as just base w/o offset.
+                //   https://wiki.osdev.org/X86-64_Instruction_Encoding#32.2F64-bit_addressing_2
+                // Disallow this case, as guard for the user.
+                assert!(!matches!(op1.index(), Reg64::rsp));
+                (0b00, 0b100)
+            }
         };
 
         let modrm = modrm(
-            mode,             /* mode */
-            op2.idx(),        /* reg */
-            op1.base().idx(), /* rm */
+            mode,      /* mode */
+            op2.idx(), /* reg */
+            rm,        /* 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());
+        match op1 {
+            MemOp::Indirect(..) => {}
+            MemOp::IndirectDisp(_, disp) => self.emit(&disp.to_ne_bytes()),
+            MemOp::IndirectBaseIndex(base, index) => self.emit(&[sib(0, index.idx(), base.idx())]),
         }
     }
 
@@ -650,8 +835,13 @@
     }
 
     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()))
+        if op2.need_rex() || op1.base().is_ext() || op1.index().is_ext() {
+            Some(rex(
+                op2.rexw(),
+                op2.idx(),
+                op1.index().idx(),
+                op1.base().idx(),
+            ))
         } else {
             None
         }
@@ -674,8 +864,8 @@
     }
 
     fn rex(op1: &MemOp) -> Option<u8> {
-        if op1.base().is_ext() {
-            Some(rex(false, 0, 0, op1.base().idx()))
+        if op1.base().is_ext() || op1.index().is_ext() {
+            Some(rex(false, 0, op1.index().idx(), op1.base().idx()))
         } else {
             None
         }
@@ -689,4 +879,41 @@
     }
 }
 impl EncodeMI<Imm32> for Asm {}
+
+/// Encode helper for memory operand instructions.
+pub(crate) trait EncodeM<T: MemOpSized> {
+    fn legacy_prefix() -> Option<u8> {
+        None
+    }
+
+    fn rex(op1: &MemOp) -> Option<u8> {
+        if op1.base().is_ext() || op1.index().is_ext() || Self::is_64bit() {
+            Some(rex(
+                Self::is_64bit(),
+                0,
+                op1.index().idx(),
+                op1.base().idx(),
+            ))
+        } else {
+            None
+        }
+    }
+
+    fn is_64bit() -> bool {
+        false
+    }
+}
+
+impl EncodeM<MemOp8> for Asm {}
+impl EncodeM<MemOp16> for Asm {
+    fn legacy_prefix() -> Option<u8> {
+        Some(0x66)
+    }
+}
+impl EncodeM<MemOp32> for Asm {}
+impl EncodeM<MemOp64> for Asm {
+    fn is_64bit() -> bool {
+        true
+    }
+}
 
\ No newline at end of file -- cgit v1.2.3