diff options
author | johannst <johannst@users.noreply.github.com> | 2024-12-13 21:12:22 +0000 |
---|---|---|
committer | johannst <johannst@users.noreply.github.com> | 2024-12-13 21:12:22 +0000 |
commit | efd6fd88d2c73ae48ff74ba9e772e2347009fe9e (patch) | |
tree | 72fb755ffc8f3e5b250c20e9596c107ff5ed2c61 /src/bf/bf.rs.html | |
parent | 22f0c8c5d4b3604227187b9843737c23be75ba75 (diff) | |
download | juicebox-asm-efd6fd88d2c73ae48ff74ba9e772e2347009fe9e.tar.gz juicebox-asm-efd6fd88d2c73ae48ff74ba9e772e2347009fe9e.zip |
deploy: e6095b086f6e2429fb952ae75a193dc89b4b9082
Diffstat (limited to 'src/bf/bf.rs.html')
-rw-r--r-- | src/bf/bf.rs.html | 184 |
1 files changed, 157 insertions, 27 deletions
diff --git a/src/bf/bf.rs.html b/src/bf/bf.rs.html index b29403b..556b131 100644 --- a/src/bf/bf.rs.html +++ b/src/bf/bf.rs.html @@ -337,7 +337,72 @@ <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></pre></div><pre class="rust"><code><span class="doccomment">//! Brainfuck VM. +<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></pre></div><pre class="rust"><code><span class="doccomment">//! Brainfuck VM. //! //! This example implements a simple //! [brainfuck](https://en.wikipedia.org/wiki/Brainfuck) interpreter @@ -514,11 +579,20 @@ <span class="comment">// Use callee saved registers to hold vm state, such that we don't need to // save any state before calling out to putchar. </span><span class="kw">let </span>dmem_base = Reg64::rbx; - <span class="kw">let </span>dmem_idx = Reg64::r12; + <span class="kw">let </span>dmem_size = Reg64::r12; + <span class="kw">let </span>dmem_idx = Reg64::r13; <span class="kw">let </span><span class="kw-2">mut </span>asm = Asm::new(); + + <span class="comment">// Save callee saved registers before we tamper them. + </span>asm.push(dmem_base); + asm.push(dmem_size); + asm.push(dmem_idx); + <span class="comment">// Move data memory pointer (argument on jit entry) into correct register. </span>asm.mov(dmem_base, Reg64::rdi); + <span class="comment">// Move data memory size into correct register. + </span>asm.mov(dmem_size, Reg64::rsi); <span class="comment">// Clear data memory index. </span>asm.xor(dmem_idx, dmem_idx); @@ -526,17 +600,28 @@ // given '[]' pair. </span><span class="kw">let </span><span class="kw-2">mut </span>label_stack = Vec::new(); + <span class="comment">// Label to jump to when a data pointer overflow is detected. + </span><span class="kw">let </span><span class="kw-2">mut </span>oob_ov = Label::new(); + <span class="comment">// Label to jump to when a data pointer underflow is detected. + </span><span class="kw">let </span><span class="kw-2">mut </span>oob_uv = Label::new(); + <span class="comment">// Generate code for each instruction in the bf program. </span><span class="kw">let </span><span class="kw-2">mut </span>pc = <span class="number">0</span>; <span class="kw">while </span>pc < vm.imem.len() { <span class="kw">match </span>vm.imem[pc] { <span class="string">'>' </span>=> { - <span class="comment">// TODO: generate runtime bounds check. - </span>asm.inc(dmem_idx); + asm.inc(dmem_idx); + + <span class="comment">// Check for data pointer overflow and jump to error handler if needed. + </span>asm.cmp(dmem_idx, dmem_size); + asm.jz(<span class="kw-2">&mut </span>oob_ov); } <span class="string">'<' </span>=> { - <span class="comment">// TODO: generate runtime bounds check. - </span>asm.dec(dmem_idx); + <span class="comment">// Check for data pointer underflow and jump to error handler if needed. + </span>asm.test(dmem_idx, dmem_idx); + asm.jz(<span class="kw-2">&mut </span>oob_uv); + + asm.dec(dmem_idx); } <span class="string">'+' </span>=> { <span class="comment">// Apply optimization to fold consecutive '+' instructions to a @@ -546,10 +631,8 @@ <span class="number">1 </span>=> { asm.inc(Mem8::indirect_base_index(dmem_base, dmem_idx)); } - cnt <span class="kw">if </span>cnt <= i8::MAX <span class="kw">as </span>usize => { - <span class="comment">// For add m64, imm8, the immediate is sign-extend and - // hence treated as signed. - </span>asm.add( + cnt <span class="kw">if </span>cnt <= u8::MAX <span class="kw">as </span>usize => { + asm.add( Mem8::indirect_base_index(dmem_base, dmem_idx), Imm8::from(cnt <span class="kw">as </span>u8), ); @@ -569,10 +652,8 @@ <span class="number">1 </span>=> { asm.dec(Mem8::indirect_base_index(dmem_base, dmem_idx)); } - cnt <span class="kw">if </span>cnt <= i8::MAX <span class="kw">as </span>usize => { - <span class="comment">// For sub m64, imm8, the immediate is sign-extend and - // hence treated as signed. - </span>asm.sub( + cnt <span class="kw">if </span>cnt <= u8::MAX <span class="kw">as </span>usize => { + asm.sub( Mem8::indirect_base_index(dmem_base, dmem_idx), Imm8::from(cnt <span class="kw">as </span>u8), ); @@ -639,30 +720,48 @@ </span>pc += <span class="number">1</span>; } - <span class="comment">// Return from bf program. - </span>asm.ret(); + <span class="kw">let </span><span class="kw-2">mut </span>ret_epilogue = Label::new(); + + <span class="comment">// Successful return from bf program. + </span>asm.xor(Reg64::rax, Reg64::rax); + asm.bind(<span class="kw-2">&mut </span>ret_epilogue); + <span class="comment">// Restore callee saved registers before returning from jit. + </span>asm.pop(dmem_idx); + asm.pop(dmem_size); + asm.pop(dmem_base); + asm.ret(); + + <span class="comment">// Return because of data pointer overflow. + </span>asm.bind(<span class="kw-2">&mut </span>oob_ov); + asm.mov(Reg64::rax, Imm64::from(<span class="number">1</span>)); + asm.jmp(<span class="kw-2">&mut </span>ret_epilogue); + + <span class="comment">// Return because of data pointer underflow. + </span>asm.bind(<span class="kw-2">&mut </span>oob_uv); + asm.mov(Reg64::rax, Imm64::from(<span class="number">2</span>)); + asm.jmp(<span class="kw-2">&mut </span>ret_epilogue); <span class="kw">if </span>!label_stack.is_empty() { <span class="macro">panic!</span>(<span class="string">"encountered un-balanced brackets, left-over '[' after jitting bf program"</span>) } - <span class="comment">// Execute jitted bf program. + <span class="comment">// Get function pointer to jitted bf program. </span><span class="kw">let </span><span class="kw-2">mut </span>rt = Runtime::new(); - <span class="kw">let </span>bf_entry = <span class="kw">unsafe </span>{ rt.add_code::<<span class="kw">extern </span><span class="string">"C" </span><span class="kw">fn</span>(<span class="kw-2">*mut </span>u8)>(asm.into_code()) }; - bf_entry(<span class="kw-2">&mut </span>vm.dmem <span class="kw">as </span><span class="kw-2">*mut </span>u8); + <span class="kw">let </span>bf_entry = <span class="kw">unsafe </span>{ rt.add_code::<<span class="kw">extern </span><span class="string">"C" </span><span class="kw">fn</span>(<span class="kw-2">*mut </span>u8, usize) -> u64>(asm.into_code()) }; + + <span class="comment">// Execute jitted bf program. + </span><span class="kw">match </span>bf_entry(<span class="kw-2">&mut </span>vm.dmem <span class="kw">as </span><span class="kw-2">*mut </span>u8, vm.dmem.len()) { + <span class="number">0 </span>=> {} + <span class="number">1 </span>=> <span class="macro">panic!</span>(<span class="string">"oob: data pointer overflow"</span>), + <span class="number">2 </span>=> <span class="macro">panic!</span>(<span class="string">"oob: data pointer underflow"</span>), + <span class="kw">_ </span>=> <span class="macro">unreachable!</span>(), + } } <span class="comment">// -- MAIN --------------------------------------------------------------------- </span><span class="kw">fn </span>main() { - <span class="comment">// https://en.wikipedia.org/wiki/Brainfuck#Adding_two_values - //let inp = "++>+++++ [<+>-] ++++++++[<++++++>-]<."; - //println!("add-print-7 (wikipedia.org) - interp"); - //run_interp(inp); - //println!("add-print-7 (wikipedia.org) - jit"); - //run_jit(inp); - - // https://en.wikipedia.org/wiki/Brainfuck#Hello_World! + <span class="comment">// https://en.wikipedia.org/wiki/Brainfuck#Hello_World! </span><span class="kw">let </span>inp = <span class="string">"++++++++[>++++[>++>+++>+++>+<<<<-]>+>+>->>+[<]<-]>>.>---.+++++++..+++.>>.<-.<.+++.------.--------.>>+.>++."</span>; <span class="macro">println!</span>(<span class="string">"hello-world (wikipedia.org) - interp"</span>); run_interp(inp); @@ -676,4 +775,35 @@ <span class="macro">println!</span>(<span class="string">"hello-world (programmingwiki.de) - jit"</span>); run_jit(inp); } + +<span class="attr">#[cfg(test)] +</span><span class="kw">mod </span>test { + <span class="kw">use super</span>::<span class="kw-2">*</span>; + + <span class="attr">#[test] + </span><span class="kw">fn </span>data_ptr_no_overflow() { + <span class="kw">let </span>inp = std::iter::repeat(<span class="string">'>'</span>).take(<span class="number">255</span>).collect::<String>(); + run_jit(<span class="kw-2">&</span>inp); + } + + <span class="attr">#[test] + #[should_panic] + </span><span class="kw">fn </span>data_ptr_overflow() { + <span class="kw">let </span>inp = std::iter::repeat(<span class="string">'>'</span>).take(<span class="number">255 </span>+ <span class="number">1</span>).collect::<String>(); + run_jit(<span class="kw-2">&</span>inp); + } + + <span class="attr">#[test] + </span><span class="kw">fn </span>data_ptr_no_underflow() { + <span class="kw">let </span>inp = <span class="string">">><< ><"</span>; + run_jit(inp); + } + + <span class="attr">#[test] + #[should_panic] + </span><span class="kw">fn </span>data_ptr_underflow() { + <span class="kw">let </span>inp = <span class="string">">><< >< <"</span>; + run_jit(<span class="kw-2">&</span>inp); + } +} </code></pre></div></section></main></body></html>
\ No newline at end of file |