diff options
Diffstat (limited to 'src/juicebox_asm/lib.rs.html')
-rw-r--r-- | src/juicebox_asm/lib.rs.html | 286 |
1 files changed, 249 insertions, 37 deletions
diff --git a/src/juicebox_asm/lib.rs.html b/src/juicebox_asm/lib.rs.html index 7b17af1..47e6bf6 100644 --- a/src/juicebox_asm/lib.rs.html +++ b/src/juicebox_asm/lib.rs.html @@ -302,26 +302,214 @@ <a href="#302" id="302">302</a> <a href="#303" id="303">303</a> <a href="#304" id="304">304</a> -</pre><pre class="rust"><code><span class="kw">pub mod </span>prelude; -<span class="kw">pub mod </span>rt; +<a href="#305" id="305">305</a> +<a href="#306" id="306">306</a> +<a href="#307" id="307">307</a> +<a href="#308" id="308">308</a> +<a href="#309" id="309">309</a> +<a href="#310" id="310">310</a> +<a href="#311" id="311">311</a> +<a href="#312" id="312">312</a> +<a href="#313" id="313">313</a> +<a href="#314" id="314">314</a> +<a href="#315" id="315">315</a> +<a href="#316" id="316">316</a> +<a href="#317" id="317">317</a> +<a href="#318" id="318">318</a> +<a href="#319" id="319">319</a> +<a href="#320" id="320">320</a> +<a href="#321" id="321">321</a> +<a href="#322" id="322">322</a> +<a href="#323" id="323">323</a> +<a href="#324" id="324">324</a> +<a href="#325" id="325">325</a> +<a href="#326" id="326">326</a> +<a href="#327" id="327">327</a> +<a href="#328" id="328">328</a> +<a href="#329" id="329">329</a> +<a href="#330" id="330">330</a> +<a href="#331" id="331">331</a> +<a href="#332" id="332">332</a> +<a href="#333" id="333">333</a> +<a href="#334" id="334">334</a> +<a href="#335" id="335">335</a> +<a href="#336" id="336">336</a> +<a href="#337" id="337">337</a> +<a href="#338" id="338">338</a> +<a href="#339" id="339">339</a> +<a href="#340" id="340">340</a> +<a href="#341" id="341">341</a> +<a href="#342" id="342">342</a> +<a href="#343" id="343">343</a> +<a href="#344" id="344">344</a> +<a href="#345" id="345">345</a> +<a href="#346" id="346">346</a> +<a href="#347" id="347">347</a> +<a href="#348" id="348">348</a> +<a href="#349" id="349">349</a> +<a href="#350" id="350">350</a> +<a href="#351" id="351">351</a> +<a href="#352" id="352">352</a> +<a href="#353" id="353">353</a> +<a href="#354" id="354">354</a> +<a href="#355" id="355">355</a> +<a href="#356" id="356">356</a> +<a href="#357" id="357">357</a> +<a href="#358" id="358">358</a> +<a href="#359" id="359">359</a> +<a href="#360" id="360">360</a> +<a href="#361" id="361">361</a> +<a href="#362" id="362">362</a> +<a href="#363" id="363">363</a> +<a href="#364" id="364">364</a> +<a href="#365" id="365">365</a> +<a href="#366" id="366">366</a> +<a href="#367" id="367">367</a> +<a href="#368" id="368">368</a> +<a href="#369" id="369">369</a> +<a href="#370" id="370">370</a> +<a href="#371" id="371">371</a> +<a href="#372" id="372">372</a> +<a href="#373" id="373">373</a> +<a href="#374" id="374">374</a> +<a href="#375" id="375">375</a> +<a href="#376" id="376">376</a> +<a href="#377" id="377">377</a> +<a href="#378" id="378">378</a> +<a href="#379" id="379">379</a> +<a href="#380" id="380">380</a> +<a href="#381" id="381">381</a> +<a href="#382" id="382">382</a> +<a href="#383" id="383">383</a> +<a href="#384" id="384">384</a> +<a href="#385" id="385">385</a> +<a href="#386" id="386">386</a> +<a href="#387" id="387">387</a> +<a href="#388" id="388">388</a> +<a href="#389" id="389">389</a> +<a href="#390" id="390">390</a> +<a href="#391" id="391">391</a> +<a href="#392" id="392">392</a> +<a href="#393" id="393">393</a> +<a href="#394" id="394">394</a> +<a href="#395" id="395">395</a> +<a href="#396" id="396">396</a> +<a href="#397" id="397">397</a> +<a href="#398" id="398">398</a> +<a href="#399" id="399">399</a> +<a href="#400" id="400">400</a> +<a href="#401" id="401">401</a> +<a href="#402" id="402">402</a> +<a href="#403" id="403">403</a> +<a href="#404" id="404">404</a> +<a href="#405" id="405">405</a> +<a href="#406" id="406">406</a> +<a href="#407" id="407">407</a> +<a href="#408" id="408">408</a> +<a href="#409" id="409">409</a> +<a href="#410" id="410">410</a> +</pre><pre class="rust"><code><span class="doccomment">//! 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::Runtime; +//! +//! const fn fib_rs(n: u64) -> u64 { +//! match n { +//! 0 => 0, +//! 1 => 1, +//! _ => fib_rs(n - 2) + fib_rs(n - 1), +//! } +//! } +//! +//! fn main() { +//! let mut asm = Asm::new(); +//! +//! let mut lp = Label::new(); +//! let mut end = Label::new(); +//! +//! // Reference implementation: +//! // +//! // int fib(int n) { +//! // int tmp = 0; +//! // int prv = 1; +//! // int sum = 0; +//! // loop: +//! // if (n == 0) goto end; +//! // tmp = sum; +//! // sum += prv; +//! // prv = tmp; +//! // --n; +//! // goto loop; +//! // end: +//! // return sum; +//! // } +//! +//! // SystemV abi: +//! // rdi -> first argument +//! // rax -> return value +//! let n = Reg64::rdi; +//! let sum = Reg64::rax; +//! +//! let tmp = Reg64::rcx; +//! let prv = Reg64::rbx; +//! +//! asm.mov(tmp, Imm64::from(0)); +//! asm.mov(prv, Imm64::from(1)); +//! asm.mov(sum, Imm64::from(0)); +//! +//! asm.bind(&mut lp); +//! asm.test(n, n); +//! asm.jz(&mut end); +//! asm.mov(tmp, sum); +//! asm.add(sum, prv); +//! asm.mov(prv, tmp); +//! asm.dec(n); +//! asm.jmp(&mut lp); +//! asm.bind(&mut end); +//! asm.ret(); +//! +//! // Move code into executable page and get function pointer to it. +//! let rt = Runtime::new(&asm.into_code()); +//! let fib = unsafe { rt.as_fn::<extern "C" fn(u64) -> u64>() }; +//! +//! for n in 0..15 { +//! let fib_jit = fib(n); +//! println!("fib({}) = {}", n, fib_jit); +//! assert_eq!(fib_jit, fib_rs(n)); +//! } +//! } +//! ``` + +</span><span class="kw">pub mod </span>prelude; <span class="kw">mod </span>imm; <span class="kw">mod </span>insn; <span class="kw">mod </span>label; <span class="kw">mod </span>reg; +<span class="kw">mod </span>rt; + +<span class="kw">pub use </span>imm::{Imm16, Imm32, Imm64, Imm8}; +<span class="kw">pub use </span>label::Label; +<span class="kw">pub use </span>reg::{Reg16, Reg32, Reg64, Reg8}; +<span class="kw">pub use </span>rt::Runtime; <span class="kw">use </span>imm::Imm; -<span class="kw">use </span>label::Label; <span class="kw">use </span>reg::Reg; -<span class="kw">use </span>reg::{Reg16, Reg32, Reg64, Reg8}; -<span class="kw">pub enum </span>MemOp { - Indirect(Reg64), - IndirectDisp(Reg64, i32), +<span class="doccomment">/// Type representing a memory operand. +</span><span class="kw">pub enum </span>MemOp { + <span class="doccomment">/// An indirect memory operand, eg `mov [rax], rcx`. + </span>Indirect(Reg64), + + <span class="doccomment">/// An indirect memory operand with additional displacement, eg `mov [rax + 0x10], rcx`. + </span>IndirectDisp(Reg64, i32), } <span class="kw">impl </span>MemOp { - <span class="kw">const fn </span>base(<span class="kw-2">&</span><span class="self">self</span>) -> Reg64 { + <span class="doccomment">/// Get the base address register of the memory operand. + </span><span class="kw">const fn </span>base(<span class="kw-2">&</span><span class="self">self</span>) -> Reg64 { <span class="kw">match </span><span class="self">self </span>{ MemOp::Indirect(base) => <span class="kw-2">*</span>base, MemOp::IndirectDisp(base, ..) => <span class="kw-2">*</span>base, @@ -343,31 +531,42 @@ ((mod_ & <span class="number">0b11</span>) << <span class="number">6</span>) | ((reg & <span class="number">0b111</span>) << <span class="number">3</span>) | (rm & <span class="number">0b111</span>) } -<span class="kw">pub struct </span>Asm { +<span class="doccomment">/// `x64` jit assembler. +</span><span class="kw">pub struct </span>Asm { buf: Vec<u8>, } <span class="kw">impl </span>Asm { - <span class="kw">pub fn </span>new() -> Asm { - <span class="kw">let </span>buf = Vec::with_capacity(<span class="number">1024</span>); + <span class="doccomment">/// Create a new `x64` jit assembler. + </span><span class="kw">pub fn </span>new() -> Asm { + <span class="comment">// Some random default capacity. + </span><span class="kw">let </span>buf = Vec::with_capacity(<span class="number">1024</span>); Asm { buf } } - <span class="kw">pub fn </span>into_code(<span class="self">self</span>) -> Vec<u8> { + <span class="doccomment">/// Consume the assembler and get the emitted code. + </span><span class="kw">pub fn </span>into_code(<span class="self">self</span>) -> Vec<u8> { <span class="self">self</span>.buf } - <span class="kw">fn </span>emit(<span class="kw-2">&mut </span><span class="self">self</span>, bytes: <span class="kw-2">&</span>[u8]) { + <span class="doccomment">/// Emit a slice of bytes. + </span><span class="kw">fn </span>emit(<span class="kw-2">&mut </span><span class="self">self</span>, bytes: <span class="kw-2">&</span>[u8]) { <span class="self">self</span>.buf.extend_from_slice(bytes); } - <span class="kw">fn </span>emit_optional(<span class="kw-2">&mut </span><span class="self">self</span>, bytes: <span class="kw-2">&</span>[<span class="prelude-ty">Option</span><u8>]) { + <span class="doccomment">/// Emit a slice of optional bytes. + </span><span class="kw">fn </span>emit_optional(<span class="kw-2">&mut </span><span class="self">self</span>, bytes: <span class="kw-2">&</span>[<span class="prelude-ty">Option</span><u8>]) { <span class="kw">for </span>byte <span class="kw">in </span>bytes.iter().filter_map(|<span class="kw-2">&</span>b| b) { <span class="self">self</span>.buf.push(byte); } } - <span class="kw">fn </span>emit_at(<span class="kw-2">&mut </span><span class="self">self</span>, pos: usize, bytes: <span class="kw-2">&</span>[u8]) { + <span class="doccomment">/// Emit a slice of bytes at `pos`. + /// + /// # Panics + /// + /// Panics if [pos..pos+len] indexes out of bound of the underlying code buffer. + </span><span class="kw">fn </span>emit_at(<span class="kw-2">&mut </span><span class="self">self</span>, pos: usize, bytes: <span class="kw-2">&</span>[u8]) { <span class="kw">if let </span><span class="prelude-val">Some</span>(buf) = <span class="self">self</span>.buf.get_mut(pos..pos + bytes.len()) { buf.copy_from_slice(bytes); } <span class="kw">else </span>{ @@ -387,7 +586,8 @@ <span class="doccomment">/// If the [Label] is bound, patch any pending relocation. </span><span class="kw">pub fn </span>resolve(<span class="kw-2">&mut </span><span class="self">self</span>, label: <span class="kw-2">&mut </span>Label) { <span class="kw">if let </span><span class="prelude-val">Some</span>(loc) = label.location() { - <span class="kw">let </span>loc = i32::try_from(loc).expect(<span class="string">"Label location did not fit into i32."</span>); + <span class="comment">// For now we only support disp32 as label location. + </span><span class="kw">let </span>loc = i32::try_from(loc).expect(<span class="string">"Label location did not fit into i32."</span>); <span class="comment">// Resolve any pending relocations for the label. </span><span class="kw">for </span>off <span class="kw">in </span>label.offsets_mut().drain() { @@ -404,6 +604,7 @@ <span class="comment">// -- Encode utilities. + </span><span class="doccomment">/// Encode an register-register instruction. </span><span class="kw">fn </span>encode_rr<T: Reg>(<span class="kw-2">&mut </span><span class="self">self</span>, opc: u8, op1: T, op2: T) <span class="kw">where </span><span class="self">Self</span>: EncodeRR<T>, @@ -424,22 +625,25 @@ <span class="self">self</span>.emit(<span class="kw-2">&</span>[opc, modrm]); } - <span class="kw">fn </span>encode_oi<T: Reg, U: Imm>(<span class="kw-2">&mut </span><span class="self">self</span>, opc: u8, op1: T, op2: U) + <span class="doccomment">/// Encode an offset-immediate instruction. + /// Register idx is encoded in the opcode. + </span><span class="kw">fn </span>encode_oi<T: Reg, U: Imm>(<span class="kw-2">&mut </span><span class="self">self</span>, opc: u8, op1: T, op2: U) <span class="kw">where - </span><span class="self">Self</span>: EncodeRI<T>, + </span><span class="self">Self</span>: EncodeR<T>, { <span class="kw">let </span>opc = opc + (op1.idx() & <span class="number">0b111</span>); - <span class="kw">let </span>prefix = <<span class="self">Self </span><span class="kw">as </span>EncodeRI<T>>::legacy_prefix(); - <span class="kw">let </span>rex = <<span class="self">Self </span><span class="kw">as </span>EncodeRI<T>>::rex(op1); + <span class="kw">let </span>prefix = <<span class="self">Self </span><span class="kw">as </span>EncodeR<T>>::legacy_prefix(); + <span class="kw">let </span>rex = <<span class="self">Self </span><span class="kw">as </span>EncodeR<T>>::rex(op1); <span class="self">self</span>.emit_optional(<span class="kw-2">&</span>[prefix, rex]); <span class="self">self</span>.emit(<span class="kw-2">&</span>[opc]); <span class="self">self</span>.emit(op2.bytes()); } - <span class="kw">fn </span>encode_ri<T: Reg, U: Imm>(<span class="kw-2">&mut </span><span class="self">self</span>, opc: u8, opc_ext: u8, op1: T, op2: U) + <span class="doccomment">/// Encode a register-immediate instruction. + </span><span class="kw">fn </span>encode_ri<T: Reg, U: Imm>(<span class="kw-2">&mut </span><span class="self">self</span>, opc: u8, opc_ext: u8, op1: T, op2: U) <span class="kw">where - </span><span class="self">Self</span>: EncodeRI<T>, + </span><span class="self">Self</span>: EncodeR<T>, { <span class="comment">// MI operand encoding. // op1 -> modrm.rm @@ -450,17 +654,18 @@ </span>op1.idx(), <span class="comment">/* rm */ </span>); - <span class="kw">let </span>prefix = <<span class="self">Self </span><span class="kw">as </span>EncodeRI<T>>::legacy_prefix(); - <span class="kw">let </span>rex = <<span class="self">Self </span><span class="kw">as </span>EncodeRI<T>>::rex(op1); + <span class="kw">let </span>prefix = <<span class="self">Self </span><span class="kw">as </span>EncodeR<T>>::legacy_prefix(); + <span class="kw">let </span>rex = <<span class="self">Self </span><span class="kw">as </span>EncodeR<T>>::rex(op1); <span class="self">self</span>.emit_optional(<span class="kw-2">&</span>[prefix, rex]); <span class="self">self</span>.emit(<span class="kw-2">&</span>[opc, modrm]); <span class="self">self</span>.emit(op2.bytes()); } - <span class="kw">fn </span>encode_r<T: Reg>(<span class="kw-2">&mut </span><span class="self">self</span>, opc: u8, opc_ext: u8, op1: T) + <span class="doccomment">/// Encode a register instruction. + </span><span class="kw">fn </span>encode_r<T: Reg>(<span class="kw-2">&mut </span><span class="self">self</span>, opc: u8, opc_ext: u8, op1: T) <span class="kw">where - </span><span class="self">Self</span>: EncodeRI<T>, + </span><span class="self">Self</span>: EncodeR<T>, { <span class="comment">// M operand encoding. // op1 -> modrm.rm @@ -471,14 +676,15 @@ </span>op1.idx(), <span class="comment">/* rm */ </span>); - <span class="kw">let </span>prefix = <<span class="self">Self </span><span class="kw">as </span>EncodeRI<T>>::legacy_prefix(); - <span class="kw">let </span>rex = <<span class="self">Self </span><span class="kw">as </span>EncodeRI<T>>::rex(op1); + <span class="kw">let </span>prefix = <<span class="self">Self </span><span class="kw">as </span>EncodeR<T>>::legacy_prefix(); + <span class="kw">let </span>rex = <<span class="self">Self </span><span class="kw">as </span>EncodeR<T>>::rex(op1); <span class="self">self</span>.emit_optional(<span class="kw-2">&</span>[prefix, rex]); <span class="self">self</span>.emit(<span class="kw-2">&</span>[opc, modrm]); } - <span class="kw">fn </span>encode_mr<T: Reg>(<span class="kw-2">&mut </span><span class="self">self</span>, opc: u8, op1: MemOp, op2: T) + <span class="doccomment">/// Encode a memory-register instruction. + </span><span class="kw">fn </span>encode_mr<T: Reg>(<span class="kw-2">&mut </span><span class="self">self</span>, opc: u8, op1: MemOp, op2: T) <span class="kw">where </span><span class="self">Self</span>: EncodeMR<T>, { @@ -511,7 +717,8 @@ } } - <span class="kw">fn </span>encode_rm<T: Reg>(<span class="kw-2">&mut </span><span class="self">self</span>, opc: u8, op1: T, op2: MemOp) + <span class="doccomment">/// Encode a register-memory instruction. + </span><span class="kw">fn </span>encode_rm<T: Reg>(<span class="kw-2">&mut </span><span class="self">self</span>, opc: u8, op1: T, op2: MemOp) <span class="kw">where </span><span class="self">Self</span>: EncodeMR<T>, { @@ -521,7 +728,8 @@ </span><span class="self">self</span>.encode_mr(opc, op2, op1); } - <span class="kw">fn </span>encode_jmp_label(<span class="kw-2">&mut </span><span class="self">self</span>, opc: <span class="kw-2">&</span>[u8], op1: <span class="kw-2">&mut </span>Label) { + <span class="doccomment">/// Encode a jump to label instruction. + </span><span class="kw">fn </span>encode_jmp_label(<span class="kw-2">&mut </span><span class="self">self</span>, opc: <span class="kw-2">&</span>[u8], op1: <span class="kw-2">&mut </span>Label) { <span class="comment">// Emit the opcode. </span><span class="self">self</span>.emit(opc); @@ -529,6 +737,7 @@ </span>op1.record_offset(<span class="self">self</span>.buf.len()); <span class="comment">// Emit a zeroed disp32, which serves as placeholder for the relocation. + // We currently only support disp32 jump targets. </span><span class="self">self</span>.emit(<span class="kw-2">&</span>[<span class="number">0u8</span>; <span class="number">4</span>]); <span class="comment">// Resolve any pending relocations for the label. @@ -538,6 +747,7 @@ <span class="comment">// -- Encoder helper. +</span><span class="doccomment">/// Encode helper for register-register instructions. </span><span class="kw">trait </span>EncodeRR<T: Reg> { <span class="kw">fn </span>legacy_prefix() -> <span class="prelude-ty">Option</span><u8> { <span class="prelude-val">None @@ -561,7 +771,8 @@ } <span class="kw">impl </span>EncodeRR<Reg64> <span class="kw">for </span>Asm {} -<span class="kw">trait </span>EncodeRI<T: Reg> { +<span class="doccomment">/// Encode helper for register instructions. +</span><span class="kw">trait </span>EncodeR<T: Reg> { <span class="kw">fn </span>legacy_prefix() -> <span class="prelude-ty">Option</span><u8> { <span class="prelude-val">None </span>} @@ -575,16 +786,17 @@ } } -<span class="kw">impl </span>EncodeRI<Reg8> <span class="kw">for </span>Asm {} -<span class="kw">impl </span>EncodeRI<Reg32> <span class="kw">for </span>Asm {} -<span class="kw">impl </span>EncodeRI<Reg16> <span class="kw">for </span>Asm { +<span class="kw">impl </span>EncodeR<Reg8> <span class="kw">for </span>Asm {} +<span class="kw">impl </span>EncodeR<Reg32> <span class="kw">for </span>Asm {} +<span class="kw">impl </span>EncodeR<Reg16> <span class="kw">for </span>Asm { <span class="kw">fn </span>legacy_prefix() -> <span class="prelude-ty">Option</span><u8> { <span class="prelude-val">Some</span>(<span class="number">0x66</span>) } } -<span class="kw">impl </span>EncodeRI<Reg64> <span class="kw">for </span>Asm {} +<span class="kw">impl </span>EncodeR<Reg64> <span class="kw">for </span>Asm {} -<span class="kw">trait </span>EncodeMR<T: Reg> { +<span class="doccomment">/// Encode helper for memory-register instructions. +</span><span class="kw">trait </span>EncodeMR<T: Reg> { <span class="kw">fn </span>legacy_prefix() -> <span class="prelude-ty">Option</span><u8> { <span class="prelude-val">None </span>} |