From d3e1eff9593501ff8677b9399e1f0625f415ec78 Mon Sep 17 00:00:00 2001 From: johannst Date: Thu, 7 Dec 2023 23:53:44 +0000 Subject: deploy: b5aea3fb5fcce31599e3d7397d5413a934132231 --- src/juicebox_asm/lib.rs.html | 736 +------------------------------------------ 1 file changed, 6 insertions(+), 730 deletions(-) (limited to 'src/juicebox_asm/lib.rs.html') diff --git a/src/juicebox_asm/lib.rs.html b/src/juicebox_asm/lib.rs.html index 83c8f81..7d1bc0c 100644 --- a/src/juicebox_asm/lib.rs.html +++ b/src/juicebox_asm/lib.rs.html @@ -105,373 +105,12 @@ 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 -324 -325 -326 -327 -328 -329 -330 -331 -332 -333 -334 -335 -336 -337 -338 -339 -340 -341 -342 -343 -344 -345 -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 -460 -461 -462 -463 -464 -465 -466 -467 -468 -469
//! A simple `x64` jit assembler with a minimal runtime to execute emitted code for fun.
 //!
 //! The following is an fibonacci example implementation.
 //! ```rust
-//! use juicebox_asm::prelude::*;
+//! use juicebox_asm::{Asm, Reg64, Imm64, Label};
+//! use juicebox_asm::insn::*;
 //! use juicebox_asm::Runtime;
 //!
 //! const fn fib_rs(n: u64) -> u64 {
@@ -541,22 +180,20 @@
 //! }
 //! ```
 
-pub mod prelude;
-
+mod asm;
 mod imm;
-mod insn;
 mod label;
 mod reg;
 mod rt;
 
+pub mod insn;
+
+pub use asm::Asm;
 pub use imm::{Imm16, Imm32, Imm64, Imm8};
 pub use label::Label;
 pub use reg::{Reg16, Reg32, Reg64, Reg8};
 pub use rt::Runtime;
 
-use imm::Imm;
-use reg::Reg;
-
 /// Type representing a memory operand.
 pub enum MemOp {
     /// An indirect memory operand, eg `mov [rax], rcx`.
@@ -575,365 +212,4 @@
         }
     }
 }
-
-/// 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)
-}
-
-/// `x64` jit assembler.
-pub struct Asm {
-    buf: Vec<u8>,
-}
-
-impl Asm {
-    /// Create a new `x64` jit assembler.
-    pub fn new() -> Asm {
-        // Some random default capacity.
-        let buf = Vec::with_capacity(1024);
-        Asm { buf }
-    }
-
-    /// Consume the assembler and get the emitted code.
-    pub fn into_code(self) -> Vec<u8> {
-        self.buf
-    }
-
-    /// Emit a slice of bytes.
-    fn emit(&mut self, bytes: &[u8]) {
-        self.buf.extend_from_slice(bytes);
-    }
-
-    /// Emit a slice of optional bytes.
-    fn emit_optional(&mut self, bytes: &[Option<u8>]) {
-        for byte in bytes.iter().filter_map(|&b| b) {
-            self.buf.push(byte);
-        }
-    }
-
-    /// Emit a slice of bytes at `pos`.
-    ///
-    /// # Panics
-    ///
-    /// Panics if [pos..pos+len] indexes out of bound of the underlying code buffer.
-    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() {
-            // For now we only support disp32 as 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.
-
-    /// Encode an register-register instruction.
-    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]);
-    }
-
-    /// Encode an offset-immediate instruction.
-    /// Register idx is encoded in the opcode.
-    fn encode_oi<T: Reg, U: Imm>(&mut self, opc: u8, op1: T, op2: U)
-    where
-        Self: EncodeR<T>,
-    {
-        let opc = opc + (op1.idx() & 0b111);
-        let prefix = <Self as EncodeR<T>>::legacy_prefix();
-        let rex = <Self as EncodeR<T>>::rex(op1);
-
-        self.emit_optional(&[prefix, rex]);
-        self.emit(&[opc]);
-        self.emit(op2.bytes());
-    }
-
-    /// Encode a register-immediate instruction.
-    fn encode_ri<T: Reg, U: Imm>(&mut self, opc: u8, opc_ext: u8, op1: T, op2: U)
-    where
-        Self: EncodeR<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 EncodeR<T>>::legacy_prefix();
-        let rex = <Self as EncodeR<T>>::rex(op1);
-
-        self.emit_optional(&[prefix, rex]);
-        self.emit(&[opc, modrm]);
-        self.emit(op2.bytes());
-    }
-
-    /// Encode a register instruction.
-    fn encode_r<T: Reg>(&mut self, opc: u8, opc_ext: u8, op1: T)
-    where
-        Self: EncodeR<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 EncodeR<T>>::legacy_prefix();
-        let rex = <Self as EncodeR<T>>::rex(op1);
-
-        self.emit_optional(&[prefix, rex]);
-        self.emit(&[opc, modrm]);
-    }
-
-    /// Encode a memory-immediate instruction.
-    fn encode_mi<T: Imm>(&mut self, opc: u8, opc_ext: u8, op1: MemOp, op2: T)
-    where
-        Self: EncodeMI<T>,
-    {
-        // MI operand encoding.
-        //   op1 -> modrm.rm
-        //   op2 -> imm
-        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 */
-            opc_ext,          /* reg */
-            op1.base().idx(), /* rm */
-        );
-
-        let prefix = <Self as EncodeMI<T>>::legacy_prefix();
-        let rex = <Self as EncodeMI<T>>::rex(&op1);
-
-        self.emit_optional(&[prefix, rex]);
-        self.emit(&[opc, modrm]);
-        if let MemOp::IndirectDisp(_, disp) = op1 {
-            self.emit(&disp.to_ne_bytes());
-        }
-        self.emit(op2.bytes());
-    }
-
-    /// Encode a memory-register instruction.
-    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());
-        }
-    }
-
-    /// Encode a register-memory instruction.
-    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);
-    }
-
-    /// Encode a jump to label instruction.
-    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.
-        // We currently only support disp32 jump targets.
-        self.emit(&[0u8; 4]);
-
-        // Resolve any pending relocations for the label.
-        self.resolve(op1);
-    }
-}
-
-// -- Encoder helper.
-
-/// Encode helper for register-register instructions.
-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 {}
-
-/// Encode helper for register instructions.
-trait EncodeR<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 EncodeR<Reg8> for Asm {}
-impl EncodeR<Reg32> for Asm {}
-impl EncodeR<Reg16> for Asm {
-    fn legacy_prefix() -> Option<u8> {
-        Some(0x66)
-    }
-}
-impl EncodeR<Reg64> for Asm {}
-
-/// Encode helper for memory-register instructions.
-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 {}
-
-/// Encode helper for memory-immediate instructions.
-trait EncodeMI<T: Imm> {
-    fn legacy_prefix() -> Option<u8> {
-        None
-    }
-
-    fn rex(op1: &MemOp) -> Option<u8> {
-        if op1.base().is_ext() {
-            Some(rex(false, 0, 0, op1.base().idx()))
-        } else {
-            None
-        }
-    }
-}
-
-impl EncodeMI<Imm8> for Asm {}
-impl EncodeMI<Imm16> for Asm {
-    fn legacy_prefix() -> Option<u8> {
-        Some(0x66)
-    }
-}
-impl EncodeMI<Imm32> for Asm {}
 
\ No newline at end of file -- cgit v1.2.3