├── doc ├── .gitignore ├── examples │ ├── bf-jit │ │ ├── test.bin │ │ ├── Cargo.toml │ │ └── src │ │ │ ├── x64.rs │ │ │ └── aarch64.rs │ ├── hello world.bf │ ├── bf-interpreter │ │ ├── Cargo.toml │ │ └── src │ │ │ └── main.rs │ ├── README.md │ └── hello-world │ │ ├── Cargo.toml │ │ └── src │ │ ├── x64.rs │ │ └── aarch64.rs ├── insref │ ├── Cargo.toml │ └── src │ │ ├── main.rs │ │ └── export.rs ├── formatting.css ├── post.html ├── hack.js ├── pre.html ├── index.md ├── releasenotes.md ├── langref_common.md └── langref_x64.md ├── testing ├── tests │ ├── gen_x64 │ │ ├── avx512.rs.gen │ │ ├── avx512bw.rs.gen │ │ ├── avx512cd.rs.gen │ │ ├── avx512dq.rs.gen │ │ ├── avx512er.rs.gen │ │ ├── avx512pf.rs.gen │ │ ├── avx512vl.rs.gen │ │ ├── sse42.rs.gen │ │ ├── avx512ifma.rs.gen │ │ ├── avx512vbmi.rs.gen │ │ ├── prefetchwt1.rs.gen │ │ ├── invpcid.rs.gen │ │ ├── rtm.rs.gen │ │ └── amd.rs.gen │ ├── fpu.rs │ ├── amd.rs │ ├── avx.rs │ ├── avx2.rs │ ├── bmi1.rs │ ├── bmi2.rs │ ├── cyrix.rs │ ├── fma.rs │ ├── mmx.rs │ ├── mpx.rs │ ├── rtm.rs │ ├── sha.rs │ ├── sse.rs │ ├── sse2.rs │ ├── sse3.rs │ ├── sse4a.rs │ ├── sse5.rs │ ├── tbm.rs │ ├── vmx.rs │ ├── avx512.rs │ ├── avx512er.rs │ ├── sse41.rs │ ├── sse42.rs │ ├── ssse3.rs │ ├── tdnow.rs │ ├── avx512bw.rs │ ├── avx512cd.rs │ ├── avx512dq.rs │ ├── avx512pf.rs │ ├── avx512vl.rs │ ├── generic.rs │ ├── invpcid.rs │ ├── avx512ifma.rs │ ├── avx512vbmi.rs │ ├── prefetchwt1.rs │ ├── aarch64_1.rs │ ├── aarch64_0.rs │ ├── aarch64_2.rs │ ├── aarch64_3.rs │ ├── aarch64_4.rs │ ├── aarch64_5.rs │ ├── aarch64_6.rs │ ├── aarch64_7.rs │ ├── aarch64_8.rs │ ├── bugreports.rs │ └── complex1.rs ├── src │ └── main.rs └── Cargo.toml ├── .travis.yml ├── .gitignore ├── runtime ├── Cargo.toml └── src │ ├── x64.rs │ ├── mmap.rs │ ├── relocations.rs │ └── x86.rs ├── tools ├── README.md ├── aarch64_compile_tests.py ├── aarch64_emit_tests.py ├── aarch64_data │ ├── tl_system.py │ ├── tl_fpsimd.py │ └── tl_float.py └── aarch64_gen_tests.py ├── plugin ├── Cargo.toml └── src │ ├── arch │ ├── mod.rs │ ├── aarch64 │ │ ├── mod.rs │ │ └── encoding_helpers.rs │ └── x64 │ │ ├── mod.rs │ │ ├── debug.rs │ │ └── ast.rs │ ├── parse_helpers.rs │ ├── directive.rs │ └── common.rs └── README.md /doc/.gitignore: -------------------------------------------------------------------------------- 1 | instructionref*.md 2 | -------------------------------------------------------------------------------- /testing/tests/gen_x64/avx512.rs.gen: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /testing/tests/gen_x64/avx512bw.rs.gen: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /testing/tests/gen_x64/avx512cd.rs.gen: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /testing/tests/gen_x64/avx512dq.rs.gen: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /testing/tests/gen_x64/avx512er.rs.gen: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /testing/tests/gen_x64/avx512pf.rs.gen: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /testing/tests/gen_x64/avx512vl.rs.gen: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /testing/tests/gen_x64/sse42.rs.gen: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /testing/tests/gen_x64/avx512ifma.rs.gen: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /testing/tests/gen_x64/avx512vbmi.rs.gen: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /doc/examples/bf-jit/test.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ailisp/dynasm-rs/master/doc/examples/bf-jit/test.bin -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: rust 2 | rust: 3 | - nightly 4 | script: 5 | - cd testing && cargo update && cargo test -j 1 6 | -------------------------------------------------------------------------------- /doc/examples/hello world.bf: -------------------------------------------------------------------------------- 1 | ++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++.>+.+++++++..+++.>++.<<+++++++++++++++.>.+++.------.--------.>+.>. -------------------------------------------------------------------------------- /testing/src/main.rs: -------------------------------------------------------------------------------- 1 | #![allow(unused_imports)] 2 | 3 | fn main() { 4 | println!("Please execute: cargo test --no-fail-fast") 5 | } 6 | -------------------------------------------------------------------------------- /testing/tests/fpu.rs: -------------------------------------------------------------------------------- 1 | #![allow(unused_imports)] 2 | 3 | use dynasmrt::dynasm; 4 | use dynasmrt::DynasmApi; 5 | include!("gen_x64/fpu.rs.gen"); 6 | -------------------------------------------------------------------------------- /testing/tests/amd.rs: -------------------------------------------------------------------------------- 1 | #![allow(unused_imports)] 2 | 3 | use dynasmrt::dynasm; 4 | use dynasmrt::DynasmApi; 5 | 6 | include!("gen_x64/amd.rs.gen"); 7 | -------------------------------------------------------------------------------- /testing/tests/avx.rs: -------------------------------------------------------------------------------- 1 | #![allow(unused_imports)] 2 | 3 | use dynasmrt::dynasm; 4 | use dynasmrt::DynasmApi; 5 | 6 | include!("gen_x64/avx.rs.gen"); 7 | -------------------------------------------------------------------------------- /testing/tests/avx2.rs: -------------------------------------------------------------------------------- 1 | #![allow(unused_imports)] 2 | 3 | use dynasmrt::dynasm; 4 | use dynasmrt::DynasmApi; 5 | 6 | include!("gen_x64/avx2.rs.gen"); 7 | -------------------------------------------------------------------------------- /testing/tests/bmi1.rs: -------------------------------------------------------------------------------- 1 | #![allow(unused_imports)] 2 | 3 | use dynasmrt::dynasm; 4 | use dynasmrt::DynasmApi; 5 | 6 | include!("gen_x64/bmi1.rs.gen"); 7 | -------------------------------------------------------------------------------- /testing/tests/bmi2.rs: -------------------------------------------------------------------------------- 1 | #![allow(unused_imports)] 2 | 3 | use dynasmrt::dynasm; 4 | use dynasmrt::DynasmApi; 5 | 6 | include!("gen_x64/bmi2.rs.gen"); 7 | -------------------------------------------------------------------------------- /testing/tests/cyrix.rs: -------------------------------------------------------------------------------- 1 | #![allow(unused_imports)] 2 | 3 | use dynasmrt::dynasm; 4 | use dynasmrt::DynasmApi; 5 | include!("gen_x64/cyrix.rs.gen"); 6 | -------------------------------------------------------------------------------- /testing/tests/fma.rs: -------------------------------------------------------------------------------- 1 | #![allow(unused_imports)] 2 | 3 | use dynasmrt::dynasm; 4 | use dynasmrt::DynasmApi; 5 | 6 | include!("gen_x64/fma.rs.gen"); 7 | -------------------------------------------------------------------------------- /testing/tests/mmx.rs: -------------------------------------------------------------------------------- 1 | #![allow(unused_imports)] 2 | 3 | use dynasmrt::dynasm; 4 | use dynasmrt::DynasmApi; 5 | 6 | include!("gen_x64/mmx.rs.gen"); 7 | -------------------------------------------------------------------------------- /testing/tests/mpx.rs: -------------------------------------------------------------------------------- 1 | #![allow(unused_imports)] 2 | 3 | use dynasmrt::dynasm; 4 | use dynasmrt::DynasmApi; 5 | 6 | include!("gen_x64/mpx.rs.gen"); 7 | -------------------------------------------------------------------------------- /testing/tests/rtm.rs: -------------------------------------------------------------------------------- 1 | #![allow(unused_imports)] 2 | 3 | use dynasmrt::dynasm; 4 | use dynasmrt::DynasmApi; 5 | 6 | include!("gen_x64/rtm.rs.gen"); 7 | -------------------------------------------------------------------------------- /testing/tests/sha.rs: -------------------------------------------------------------------------------- 1 | #![allow(unused_imports)] 2 | 3 | use dynasmrt::dynasm; 4 | use dynasmrt::DynasmApi; 5 | 6 | include!("gen_x64/sha.rs.gen"); 7 | -------------------------------------------------------------------------------- /testing/tests/sse.rs: -------------------------------------------------------------------------------- 1 | #![allow(unused_imports)] 2 | 3 | use dynasmrt::dynasm; 4 | use dynasmrt::DynasmApi; 5 | 6 | include!("gen_x64/sse.rs.gen"); 7 | -------------------------------------------------------------------------------- /testing/tests/sse2.rs: -------------------------------------------------------------------------------- 1 | #![allow(unused_imports)] 2 | 3 | use dynasmrt::dynasm; 4 | use dynasmrt::DynasmApi; 5 | 6 | include!("gen_x64/sse2.rs.gen"); 7 | -------------------------------------------------------------------------------- /testing/tests/sse3.rs: -------------------------------------------------------------------------------- 1 | #![allow(unused_imports)] 2 | 3 | use dynasmrt::dynasm; 4 | use dynasmrt::DynasmApi; 5 | 6 | include!("gen_x64/sse3.rs.gen"); 7 | -------------------------------------------------------------------------------- /testing/tests/sse4a.rs: -------------------------------------------------------------------------------- 1 | #![allow(unused_imports)] 2 | 3 | use dynasmrt::dynasm; 4 | use dynasmrt::DynasmApi; 5 | include!("gen_x64/sse4a.rs.gen"); 6 | -------------------------------------------------------------------------------- /testing/tests/sse5.rs: -------------------------------------------------------------------------------- 1 | #![allow(unused_imports)] 2 | 3 | use dynasmrt::dynasm; 4 | use dynasmrt::DynasmApi; 5 | 6 | include!("gen_x64/sse5.rs.gen"); 7 | -------------------------------------------------------------------------------- /testing/tests/tbm.rs: -------------------------------------------------------------------------------- 1 | #![allow(unused_imports)] 2 | 3 | use dynasmrt::dynasm; 4 | use dynasmrt::DynasmApi; 5 | 6 | include!("gen_x64/tbm.rs.gen"); 7 | -------------------------------------------------------------------------------- /testing/tests/vmx.rs: -------------------------------------------------------------------------------- 1 | #![allow(unused_imports)] 2 | 3 | use dynasmrt::dynasm; 4 | use dynasmrt::DynasmApi; 5 | 6 | include!("gen_x64/vmx.rs.gen"); 7 | -------------------------------------------------------------------------------- /testing/tests/avx512.rs: -------------------------------------------------------------------------------- 1 | #![allow(unused_imports)] 2 | 3 | use dynasmrt::dynasm; 4 | use dynasmrt::DynasmApi; 5 | 6 | include!("gen_x64/avx512.rs.gen"); 7 | -------------------------------------------------------------------------------- /testing/tests/avx512er.rs: -------------------------------------------------------------------------------- 1 | #![allow(unused_imports)] 2 | 3 | use dynasmrt::dynasm; 4 | use dynasmrt::DynasmApi; 5 | include!("gen_x64/avx512er.rs.gen"); 6 | -------------------------------------------------------------------------------- /testing/tests/sse41.rs: -------------------------------------------------------------------------------- 1 | #![allow(unused_imports)] 2 | 3 | use dynasmrt::dynasm; 4 | use dynasmrt::DynasmApi; 5 | 6 | include!("gen_x64/sse41.rs.gen"); 7 | -------------------------------------------------------------------------------- /testing/tests/sse42.rs: -------------------------------------------------------------------------------- 1 | #![allow(unused_imports)] 2 | 3 | use dynasmrt::dynasm; 4 | use dynasmrt::DynasmApi; 5 | 6 | include!("gen_x64/sse42.rs.gen"); 7 | -------------------------------------------------------------------------------- /testing/tests/ssse3.rs: -------------------------------------------------------------------------------- 1 | #![allow(unused_imports)] 2 | 3 | use dynasmrt::dynasm; 4 | use dynasmrt::DynasmApi; 5 | 6 | include!("gen_x64/ssse3.rs.gen"); 7 | -------------------------------------------------------------------------------- /testing/tests/tdnow.rs: -------------------------------------------------------------------------------- 1 | #![allow(unused_imports)] 2 | 3 | use dynasmrt::dynasm; 4 | use dynasmrt::DynasmApi; 5 | 6 | include!("gen_x64/tdnow.rs.gen"); 7 | -------------------------------------------------------------------------------- /testing/tests/avx512bw.rs: -------------------------------------------------------------------------------- 1 | #![allow(unused_imports)] 2 | 3 | use dynasmrt::dynasm; 4 | use dynasmrt::DynasmApi; 5 | 6 | include!("gen_x64/avx512bw.rs.gen"); 7 | -------------------------------------------------------------------------------- /testing/tests/avx512cd.rs: -------------------------------------------------------------------------------- 1 | #![allow(unused_imports)] 2 | 3 | use dynasmrt::dynasm; 4 | use dynasmrt::DynasmApi; 5 | 6 | include!("gen_x64/avx512cd.rs.gen"); 7 | -------------------------------------------------------------------------------- /testing/tests/avx512dq.rs: -------------------------------------------------------------------------------- 1 | #![allow(unused_imports)] 2 | 3 | use dynasmrt::dynasm; 4 | use dynasmrt::DynasmApi; 5 | 6 | include!("gen_x64/avx512dq.rs.gen"); 7 | -------------------------------------------------------------------------------- /testing/tests/avx512pf.rs: -------------------------------------------------------------------------------- 1 | #![allow(unused_imports)] 2 | 3 | use dynasmrt::dynasm; 4 | use dynasmrt::DynasmApi; 5 | 6 | include!("gen_x64/avx512pf.rs.gen"); 7 | -------------------------------------------------------------------------------- /testing/tests/avx512vl.rs: -------------------------------------------------------------------------------- 1 | #![allow(unused_imports)] 2 | 3 | use dynasmrt::dynasm; 4 | use dynasmrt::DynasmApi; 5 | 6 | include!("gen_x64/avx512vl.rs.gen"); 7 | -------------------------------------------------------------------------------- /testing/tests/generic.rs: -------------------------------------------------------------------------------- 1 | #![allow(unused_imports)] 2 | 3 | use dynasmrt::dynasm; 4 | use dynasmrt::DynasmApi; 5 | 6 | include!("gen_x64/generic.rs.gen"); 7 | -------------------------------------------------------------------------------- /testing/tests/invpcid.rs: -------------------------------------------------------------------------------- 1 | #![allow(unused_imports)] 2 | 3 | use dynasmrt::dynasm; 4 | use dynasmrt::DynasmApi; 5 | 6 | include!("gen_x64/invpcid.rs.gen"); 7 | -------------------------------------------------------------------------------- /testing/tests/avx512ifma.rs: -------------------------------------------------------------------------------- 1 | #![allow(unused_imports)] 2 | 3 | use dynasmrt::dynasm; 4 | use dynasmrt::DynasmApi; 5 | 6 | include!("gen_x64/avx512ifma.rs.gen"); 7 | -------------------------------------------------------------------------------- /testing/tests/avx512vbmi.rs: -------------------------------------------------------------------------------- 1 | #![allow(unused_imports)] 2 | 3 | use dynasmrt::dynasm; 4 | use dynasmrt::DynasmApi; 5 | 6 | include!("gen_x64/avx512vbmi.rs.gen"); 7 | -------------------------------------------------------------------------------- /testing/tests/prefetchwt1.rs: -------------------------------------------------------------------------------- 1 | #![allow(unused_imports)] 2 | 3 | use dynasmrt::dynasm; 4 | use dynasmrt::DynasmApi; 5 | 6 | include!("gen_x64/prefetchwt1.rs.gen"); 7 | -------------------------------------------------------------------------------- /testing/tests/aarch64_1.rs: -------------------------------------------------------------------------------- 1 | #![allow(unused_imports)] 2 | 3 | use dynasmrt::dynasm; 4 | use dynasmrt::DynasmApi; 5 | 6 | include!("gen_aarch64/aarch64_tests_1.rs.gen"); 7 | -------------------------------------------------------------------------------- /testing/tests/aarch64_0.rs: -------------------------------------------------------------------------------- 1 | #![allow(unused_imports)] 2 | 3 | use dynasmrt::dynasm; 4 | use dynasmrt::DynasmApi; 5 | 6 | include!("gen_aarch64/aarch64_tests_0.rs.gen"); 7 | 8 | -------------------------------------------------------------------------------- /testing/tests/aarch64_2.rs: -------------------------------------------------------------------------------- 1 | #![allow(unused_imports)] 2 | 3 | use dynasmrt::dynasm; 4 | use dynasmrt::DynasmApi; 5 | 6 | include!("gen_aarch64/aarch64_tests_2.rs.gen"); 7 | 8 | -------------------------------------------------------------------------------- /testing/tests/aarch64_3.rs: -------------------------------------------------------------------------------- 1 | #![allow(unused_imports)] 2 | 3 | use dynasmrt::dynasm; 4 | use dynasmrt::DynasmApi; 5 | 6 | include!("gen_aarch64/aarch64_tests_3.rs.gen"); 7 | 8 | -------------------------------------------------------------------------------- /testing/tests/aarch64_4.rs: -------------------------------------------------------------------------------- 1 | #![allow(unused_imports)] 2 | 3 | use dynasmrt::dynasm; 4 | use dynasmrt::DynasmApi; 5 | 6 | include!("gen_aarch64/aarch64_tests_4.rs.gen"); 7 | 8 | -------------------------------------------------------------------------------- /testing/tests/aarch64_5.rs: -------------------------------------------------------------------------------- 1 | #![allow(unused_imports)] 2 | 3 | use dynasmrt::dynasm; 4 | use dynasmrt::DynasmApi; 5 | 6 | include!("gen_aarch64/aarch64_tests_5.rs.gen"); 7 | 8 | -------------------------------------------------------------------------------- /testing/tests/aarch64_6.rs: -------------------------------------------------------------------------------- 1 | #![allow(unused_imports)] 2 | 3 | use dynasmrt::dynasm; 4 | use dynasmrt::DynasmApi; 5 | 6 | include!("gen_aarch64/aarch64_tests_6.rs.gen"); 7 | 8 | -------------------------------------------------------------------------------- /testing/tests/aarch64_7.rs: -------------------------------------------------------------------------------- 1 | #![allow(unused_imports)] 2 | 3 | use dynasmrt::dynasm; 4 | use dynasmrt::DynasmApi; 5 | 6 | include!("gen_aarch64/aarch64_tests_7.rs.gen"); 7 | 8 | -------------------------------------------------------------------------------- /testing/tests/aarch64_8.rs: -------------------------------------------------------------------------------- 1 | #![allow(unused_imports)] 2 | 3 | use dynasmrt::dynasm; 4 | use dynasmrt::DynasmApi; 5 | 6 | include!("gen_aarch64/aarch64_tests_8.rs.gen"); 7 | 8 | -------------------------------------------------------------------------------- /doc/examples/bf-interpreter/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "bf-int" 3 | version = "0.1.0" 4 | authors = ["CensoredUsername "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.log 2 | *.txt 3 | *.sublime-* 4 | *.exe 5 | *.pdb 6 | *.swp 7 | 8 | .python-version 9 | *.prv 10 | 11 | target/ 12 | build_docs/ 13 | Cargo.lock 14 | 15 | testing/tests/bf_interpreter*.rs 16 | testing/tests/bf_jit*.rs 17 | testing/tests/hello_world*.rs 18 | 19 | __pycache__ 20 | -------------------------------------------------------------------------------- /testing/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "testing" 3 | version = "0.1.0" 4 | authors = ["Alexander Stocko ", "CensoredUsername "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | itertools = "0.5.*" 9 | 10 | [dependencies.dynasmrt] 11 | path = "../runtime" 12 | -------------------------------------------------------------------------------- /doc/examples/README.md: -------------------------------------------------------------------------------- 1 | This folder contains several example dynasm-rs based projects. 2 | If the project contains arch-specific assembly, it will contain a binary target per architecture. 3 | 4 | Each of them can be executed with the normal `cargo run`, i.e. `cargo run --bin=aarch64` for the aarch64 version. 5 | -------------------------------------------------------------------------------- /doc/examples/hello-world/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "hello-world" 3 | version = "0.1.0" 4 | authors = ["CensoredUsername "] 5 | edition = "2018" 6 | 7 | [[bin]] 8 | name = "x64" 9 | path = "src/x64.rs" 10 | 11 | [[bin]] 12 | name = "aarch64" 13 | path = "src/aarch64.rs" 14 | 15 | [dependencies] 16 | 17 | [dependencies.dynasmrt] 18 | path = "../../../runtime" 19 | -------------------------------------------------------------------------------- /doc/examples/bf-jit/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "bf-jit" 3 | version = "0.1.0" 4 | authors = ["CensoredUsername "] 5 | edition = "2018" 6 | 7 | [[bin]] 8 | name = "x64" 9 | path = "src/x64.rs" 10 | 11 | [[bin]] 12 | name = "aarch64" 13 | path = "src/aarch64.rs" 14 | 15 | [dependencies] 16 | itertools = "0.5.*" 17 | 18 | [dependencies.dynasmrt] 19 | path = "../../../runtime" 20 | -------------------------------------------------------------------------------- /doc/insref/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "insref" 3 | version = "0.1.0" 4 | authors = ["Alexander Stocko ", "CensoredUsername "] 5 | default-run = "main" 6 | 7 | [[bin]] 8 | name = "main" 9 | path = "src/main.rs" 10 | 11 | [[bin]] 12 | name = "export" 13 | path = "src/export.rs" 14 | 15 | [dependencies] 16 | 17 | [dependencies.dynasm] 18 | path = "../../plugin" 19 | features = ["dynasm_opmap", "dynasm_extract"] 20 | -------------------------------------------------------------------------------- /doc/formatting.css: -------------------------------------------------------------------------------- 1 | @import url('../plugin/rustdoc.css'); 2 | @import url('../plugin/light.css'); 3 | 4 | code.language-diffnew { 5 | background-color: rgb(203, 255, 203); 6 | } 7 | 8 | code.language-diffold { 9 | background-color: rgb(255, 203, 203); 10 | } 11 | 12 | .block h4 { 13 | text-align: center; 14 | } 15 | 16 | pre.collapse-old { 17 | margin-bottom: 0; 18 | padding-bottom: 0; 19 | } 20 | 21 | pre.collapse-new { 22 | margin-top: 0; 23 | padding-top: 0; 24 | } 25 | -------------------------------------------------------------------------------- /doc/insref/src/main.rs: -------------------------------------------------------------------------------- 1 | use std::io::{self, Write}; 2 | 3 | fn main() { 4 | let mut args = std::env::args(); 5 | args.next().unwrap(); 6 | 7 | let opmap = match args.next().expect("Architecture name").as_str() { 8 | "x64" => dynasm::dynasm_opmap!(x64), 9 | "aarch64" => dynasm::dynasm_opmap!(aarch64), 10 | x => panic!("Unknown opmap format '{}'", x) 11 | }; 12 | 13 | let stdout = io::stdout(); 14 | let mut stdout = stdout.lock(); 15 | stdout.write_all(opmap.as_bytes()).unwrap(); 16 | } 17 | -------------------------------------------------------------------------------- /doc/insref/src/export.rs: -------------------------------------------------------------------------------- 1 | #![feature(proc_macro_hygiene)] 2 | 3 | use std::io::{self, Write}; 4 | 5 | fn main() { 6 | let mut args = std::env::args(); 7 | args.next().unwrap(); 8 | 9 | let opmap = match args.next().expect("Architecture name").as_str() { 10 | "x64" => dynasm::dynasm_extract!(x64), 11 | "aarch64" => dynasm::dynasm_extract!(aarch64), 12 | x => panic!("Unknown opmap format '{}'", x) 13 | }; 14 | 15 | let stdout = io::stdout(); 16 | let mut stdout = stdout.lock(); 17 | stdout.write_all(opmap.as_bytes()).unwrap(); 18 | } 19 | -------------------------------------------------------------------------------- /doc/post.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /runtime/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "dynasmrt" 3 | version = "1.1.0" # remember to update dynasm dependency 4 | authors = ["Alexander Stocko ", "CensoredUsername "] 5 | edition = "2018" 6 | 7 | description = "A simple runtime for assembling code at runtime. Combined with the plugin crate dynasm it can be used to write JIT compilers easily." 8 | 9 | documentation = "https://censoredusername.github.io/dynasm-rs/plugin/dynasm/index.html" 10 | repository = "https://github.com/CensoredUsername/dynasm-rs" 11 | 12 | readme = "../README.md" 13 | keywords = ["jit", "dynasm", "dynasmrt", "dynasm-rs", "assembler"] 14 | license = "MPL-2.0" 15 | 16 | 17 | [dependencies] 18 | memmap2 = "^0.2" 19 | byteorder = "1" 20 | dynasm = { version = "=1.1.0", path = "../plugin" } 21 | -------------------------------------------------------------------------------- /tools/README.md: -------------------------------------------------------------------------------- 1 | This folder contains the tools used to generate various data / test files used for dynasm. 2 | 3 | Aarch64 4 | ####### 5 | 6 | - `aarch64_gen_opmap.py`: Parses the Machine-Readable Architecture specifications for ARMv8 as produced by ARM, and combined with several translation files in the `aarch64_data` folder produces the `opmap.rs` file for the aarch64 assembler. 7 | - `aarch64_gen_tests.py`: Parses an export of this `opmap.rs` file as produced by dynasm with the `dynasm_extract` feature used and based on this file, generates a file of dynasm-dialect assembly vs gnu as-dialect assembly. 8 | - `aarch64_compile_tests.py`: Reads the previous file, feeds all the gnu as-dialect assembly lines through `as` and records the binary representation of the assembled data next to the assembly strings. 9 | - `aarch64_emit_tests.py`: Takes the output of the previous step and uses it to generate the testcases in `testing/tests/gen_aarch64` that can then be used to validate dynasm. 10 | -------------------------------------------------------------------------------- /testing/tests/gen_x64/prefetchwt1.rs.gen: -------------------------------------------------------------------------------- 1 | 2 | #[test] 3 | fn enc_prefetchwt1_prefetchwt13299() { 4 | let mut ops = dynasmrt::SimpleAssembler::new(); 5 | dynasm!(ops 6 | ; .arch x64 7 | ; prefetchwt1 BYTE [rax * 2 + rdx] 8 | ); 9 | let buf = ops.finalize(); 10 | let hex: Vec = buf.iter().map(|x| format!("0x{:02X}", *x)).collect(); 11 | let hex: String = hex.join(", "); 12 | assert_eq!(hex, "0x0F, 0x0D, 0x14, 0x42", "prefetchwt1 BYTE [rax * 2 + rdx]"); 13 | } 14 | 15 | 16 | 17 | #[test] 18 | fn enc_prefetchwt1_prefetchwt13300() { 19 | let mut ops = dynasmrt::SimpleAssembler::new(); 20 | dynasm!(ops 21 | ; .arch x64 22 | ; prefetchwt1 BYTE [rax + 16] 23 | ); 24 | let buf = ops.finalize(); 25 | let hex: Vec = buf.iter().map(|x| format!("0x{:02X}", *x)).collect(); 26 | let hex: String = hex.join(", "); 27 | assert_eq!(hex, "0x0F, 0x0D, 0x50, 0x10", "prefetchwt1 BYTE [rax + 16]"); 28 | } 29 | 30 | 31 | -------------------------------------------------------------------------------- /doc/hack.js: -------------------------------------------------------------------------------- 1 | // I'm sorry 2 | var path = document.getElementsByClassName("logo-container")[0].childNodes[0].getAttribute("src"); 3 | var nest_count = (path.match(/\.\./g)||[]).length + 1; 4 | 5 | var base_path = ""; 6 | for (i = 0; i < nest_count; i++) { 7 | base_path += "../"; 8 | } 9 | 10 | var sidebar = document.getElementsByClassName("sidebar")[0]; 11 | 12 | var node = document.createElement("div"); 13 | node.innerHTML = '\ 14 |

\ 15 | dynasm-rs\ 16 |

\ 17 |
\ 18 |

Components

\ 19 | \ 30 |
'; 31 | 32 | sidebar.insertBefore(node, sidebar.childNodes[2]); 33 | -------------------------------------------------------------------------------- /plugin/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "dynasm" 3 | version = "1.1.0" 4 | authors = ["Alexander Stocko ", "CensoredUsername "] 5 | edition = "2018" 6 | 7 | description = "A plugin for assembling code at runtime. Combined with the runtime crate dynasmrt it can be used to write JIT compilers easily." 8 | 9 | documentation = "https://censoredusername.github.io/dynasm-rs/plugin/dynasm/index.html" 10 | repository = "https://github.com/CensoredUsername/dynasm-rs" 11 | 12 | readme = "../README.md" 13 | keywords = ["jit", "dynasm", "dynasmrt", "dynasm-rs", "assembler"] 14 | license = "MPL-2.0" 15 | 16 | [lib] 17 | name = "dynasm" 18 | proc-macro = true 19 | 20 | [dependencies] 21 | lazy_static = "1" 22 | bitflags = "1" 23 | byteorder = "1" 24 | quote = "1" 25 | proc-macro-error = "1" 26 | 27 | [dependencies.syn] 28 | version = "1" 29 | features = ["full", "extra-traits"] 30 | 31 | [dependencies.proc-macro2] 32 | version = "1.0.26" 33 | 34 | [features] 35 | dynasm_opmap = [] 36 | dynasm_extract = [] 37 | filelocal = [] 38 | 39 | default = [] -------------------------------------------------------------------------------- /doc/examples/hello-world/src/x64.rs: -------------------------------------------------------------------------------- 1 | use dynasmrt::{dynasm, DynasmApi, DynasmLabelApi}; 2 | 3 | use std::{io, slice, mem}; 4 | use std::io::Write; 5 | 6 | fn main() { 7 | let mut ops = dynasmrt::x64::Assembler::new().unwrap(); 8 | let string = "Hello World!"; 9 | 10 | dynasm!(ops 11 | ; .arch x64 12 | ; ->hello: 13 | ; .bytes string.as_bytes() 14 | ); 15 | 16 | let hello = ops.offset(); 17 | dynasm!(ops 18 | ; .arch x64 19 | ; lea rcx, [->hello] 20 | ; xor edx, edx 21 | ; mov dl, BYTE string.len() as _ 22 | ; mov rax, QWORD print as _ 23 | ; sub rsp, BYTE 0x28 24 | ; call rax 25 | ; add rsp, BYTE 0x28 26 | ; ret 27 | ); 28 | 29 | let buf = ops.finalize().unwrap(); 30 | 31 | let hello_fn: extern "win64" fn() -> bool = unsafe { mem::transmute(buf.ptr(hello)) }; 32 | 33 | assert!(hello_fn()); 34 | } 35 | 36 | pub extern "win64" fn print(buffer: *const u8, length: u64) -> bool { 37 | io::stdout() 38 | .write_all(unsafe { slice::from_raw_parts(buffer, length as usize) }) 39 | .is_ok() 40 | } 41 | -------------------------------------------------------------------------------- /doc/examples/hello-world/src/aarch64.rs: -------------------------------------------------------------------------------- 1 | use dynasmrt::{dynasm, DynasmApi, DynasmLabelApi}; 2 | 3 | use std::{io, slice, mem}; 4 | use std::io::Write; 5 | 6 | fn main() { 7 | let mut ops = dynasmrt::aarch64::Assembler::new().unwrap(); 8 | let string = "Hello World!"; 9 | 10 | dynasm!(ops 11 | ; .arch aarch64 12 | ; ->hello: 13 | ; .bytes string.as_bytes() 14 | ; .align 4 15 | ; ->print: 16 | ; .qword print as _ 17 | ); 18 | 19 | let hello = ops.offset(); 20 | dynasm!(ops 21 | ; .arch aarch64 22 | ; adr x0, ->hello 23 | ; movz x1, string.len() as u32 24 | ; ldr x9, ->print 25 | ; str x30, [sp, #-16]! 26 | ; blr x9 27 | ; ldr x30, [sp], #16 28 | ; ret 29 | ); 30 | 31 | let buf = ops.finalize().unwrap(); 32 | 33 | let hello_fn: extern "C" fn() -> bool = unsafe { mem::transmute(buf.ptr(hello)) }; 34 | 35 | assert!(hello_fn()); 36 | } 37 | 38 | pub extern "C" fn print(buffer: *const u8, length: u64) -> bool { 39 | io::stdout() 40 | .write_all(unsafe { slice::from_raw_parts(buffer, length as usize) }) 41 | .is_ok() 42 | } 43 | -------------------------------------------------------------------------------- /tools/aarch64_compile_tests.py: -------------------------------------------------------------------------------- 1 | import subprocess 2 | import binascii 3 | 4 | def read_test_strings(f): 5 | buf = [] 6 | for line in f: 7 | if line: 8 | if not "\t" in line: 9 | print(line) 10 | dynasm, gas = line.split("\t") 11 | buf.append((dynasm.strip(), gas.strip())) 12 | 13 | return buf 14 | 15 | def compile_with_as(asmstring): 16 | with open("test.s", "w", encoding="utf-8") as f: 17 | f.write(asmstring) 18 | f.write("\n") 19 | 20 | subprocess.run(["as", "-mcpu=all", "test.s", "-o", "test.o"], check=True) 21 | subprocess.run(["objcopy", "-O", "binary", "test.o", "test.bin"], check=True) 22 | 23 | with open("test.bin", "rb") as f: 24 | data = f.read() 25 | return data 26 | 27 | def write_result(buf, f): 28 | for dynasm, gas, binary in buf: 29 | f.write("{}\t{}\t{}\n".format(dynasm, gas, binascii.hexlify(binary).decode("utf-8"))) 30 | 31 | def main(): 32 | import sys 33 | with open(sys.argv[1], "r", encoding="utf-8") as f: 34 | test_strings = read_test_strings(f) 35 | 36 | buf = [] 37 | for dynasm, gas in test_strings: 38 | try: 39 | binary = compile_with_as(gas) 40 | buf.append((dynasm, gas, binary)) 41 | except: 42 | print("Error at {}".format(gas)) 43 | 44 | with open(sys.argv[2], "w", encoding="utf-8") as f: 45 | write_result(buf, f) 46 | 47 | if __name__ == '__main__': 48 | main() 49 | -------------------------------------------------------------------------------- /doc/pre.html: -------------------------------------------------------------------------------- 1 | 58 |
-------------------------------------------------------------------------------- /tools/aarch64_emit_tests.py: -------------------------------------------------------------------------------- 1 | import os 2 | import os.path 3 | 4 | BLACKLIST = { 5 | "adrp" # assembler emits a bad example for this 6 | } 7 | 8 | def read_input_file(f): 9 | buf = [] 10 | for line in f: 11 | dynasm, gas, bytes = line.split("\t") 12 | buf.append((dynasm.strip(), gas.strip(), bytes.strip())) 13 | return buf 14 | 15 | def chunks(l, n): 16 | for i in range(0, len(l), n): 17 | yield l[i:i+n] 18 | 19 | def main(): 20 | import sys 21 | with open(sys.argv[1], "r", encoding="utf-8") as f: 22 | data = read_input_file(f) 23 | 24 | tests = [emit_test_case(i, dynasm, gas, bytes) for i, (dynasm, gas, bytes) in enumerate(data)] 25 | 26 | for i, chunk in enumerate(chunks(tests, 800)): 27 | with open(os.path.join(sys.argv[2], "aarch64_tests_{}.rs.gen".format(i)), "w", encoding="utf-8") as f: 28 | for test in chunk: 29 | f.write(test) 30 | 31 | def emit_test_case(i, dynasm, gas, bytes): 32 | name = dynasm.split(' ', 1)[0].replace(".", "_") 33 | if name in BLACKLIST: 34 | return "" 35 | bytes = ", ".join(chunks(bytes, 2)).upper() 36 | error = dynasm.replace("{", "{{").replace("}", "}}") 37 | return """ 38 | #[test] 39 | fn {}_{}() {{ 40 | let mut ops = dynasmrt::aarch64::Assembler::new().unwrap(); 41 | dynasm!(ops 42 | ; .arch aarch64 43 | ; {} 44 | ); 45 | let buf = ops.finalize().unwrap(); 46 | let hex: Vec = buf.iter().map(|x| format!("{{:02X}}", *x)).collect(); 47 | let hex = hex.join(", "); 48 | assert_eq!(hex, "{}", "{}"); 49 | }} 50 | """.format(name, i, dynasm, bytes, error) 51 | 52 | 53 | 54 | if __name__ == "__main__": 55 | main() 56 | -------------------------------------------------------------------------------- /testing/tests/gen_x64/invpcid.rs.gen: -------------------------------------------------------------------------------- 1 | 2 | #[test] 3 | fn enc_invpcid_invpcid5908() { 4 | let mut ops = dynasmrt::SimpleAssembler::new(); 5 | dynasm!(ops 6 | ; .arch x64 7 | ; invpcid rcx, OWORD [rax] 8 | ); 9 | let buf = ops.finalize(); 10 | let hex: Vec = buf.iter().map(|x| format!("0x{:02X}", *x)).collect(); 11 | let hex: String = hex.join(", "); 12 | assert_eq!(hex, "0x66, 0x0F, 0x38, 0x82, 0x08", "invpcid rcx, OWORD [rax]"); 13 | } 14 | 15 | 16 | 17 | #[test] 18 | fn enc_invpcid_invpcid5909() { 19 | let mut ops = dynasmrt::SimpleAssembler::new(); 20 | dynasm!(ops 21 | ; .arch x64 22 | ; invpcid rcx, OWORD [rax] 23 | ); 24 | let buf = ops.finalize(); 25 | let hex: Vec = buf.iter().map(|x| format!("0x{:02X}", *x)).collect(); 26 | let hex: String = hex.join(", "); 27 | assert_eq!(hex, "0x66, 0x0F, 0x38, 0x82, 0x08", "invpcid rcx, OWORD [rax]"); 28 | } 29 | 30 | 31 | 32 | #[test] 33 | fn enc_invpcid_invpcid5910() { 34 | let mut ops = dynasmrt::SimpleAssembler::new(); 35 | dynasm!(ops 36 | ; .arch x64 37 | ; invpcid rcx, OWORD [rax] 38 | ); 39 | let buf = ops.finalize(); 40 | let hex: Vec = buf.iter().map(|x| format!("0x{:02X}", *x)).collect(); 41 | let hex: String = hex.join(", "); 42 | assert_eq!(hex, "0x66, 0x0F, 0x38, 0x82, 0x08", "invpcid rcx, OWORD [rax]"); 43 | } 44 | 45 | 46 | 47 | #[test] 48 | fn enc_invpcid_invpcid5911() { 49 | let mut ops = dynasmrt::SimpleAssembler::new(); 50 | dynasm!(ops 51 | ; .arch x64 52 | ; invpcid rax, OWORD [rax] 53 | ); 54 | let buf = ops.finalize(); 55 | let hex: Vec = buf.iter().map(|x| format!("0x{:02X}", *x)).collect(); 56 | let hex: String = hex.join(", "); 57 | assert_eq!(hex, "0x66, 0x0F, 0x38, 0x82, 0x00", "invpcid rax, OWORD [rax]"); 58 | } 59 | 60 | 61 | -------------------------------------------------------------------------------- /plugin/src/arch/mod.rs: -------------------------------------------------------------------------------- 1 | use syn::parse; 2 | use proc_macro_error::emit_error; 3 | 4 | use crate::common::{Size, Stmt, Jump}; 5 | use crate::State; 6 | 7 | use std::fmt::Debug; 8 | 9 | pub mod x64; 10 | pub mod aarch64; 11 | 12 | pub(crate) trait Arch : Debug + Send { 13 | fn name(&self) -> &str; 14 | fn set_features(&mut self, features: &[syn::Ident]); 15 | fn handle_static_reloc(&self, stmts: &mut Vec, reloc: Jump, size: Size); 16 | fn default_align(&self) -> u8; 17 | fn compile_instruction(&self, state: &mut State, input: parse::ParseStream) -> parse::Result<()>; 18 | } 19 | 20 | #[derive(Clone, Debug)] 21 | pub struct DummyArch { 22 | name: &'static str 23 | } 24 | 25 | impl DummyArch { 26 | fn new(name: &'static str) -> DummyArch { 27 | DummyArch { name } 28 | } 29 | } 30 | 31 | impl Arch for DummyArch { 32 | fn name(&self) -> &str { 33 | self.name 34 | } 35 | 36 | fn set_features(&mut self, features: &[syn::Ident]) { 37 | if let Some(feature) = features.first() { 38 | emit_error!(feature, "Cannot set features when the assembling architecture is undefined. Define it using a .arch directive"); 39 | } 40 | } 41 | 42 | fn handle_static_reloc(&self, _stmts: &mut Vec, reloc: Jump, _size: Size) { 43 | let span = reloc.span(); 44 | emit_error!(span, "Current assembling architecture is undefined. Define it using a .arch directive"); 45 | } 46 | 47 | fn default_align(&self) -> u8 { 48 | 0 49 | } 50 | 51 | fn compile_instruction(&self, _state: &mut State, input: parse::ParseStream) -> parse::Result<()> { 52 | emit_error!(input.cursor().span(), "Current assembling architecture is undefined. Define it using a .arch directive"); 53 | Ok(()) 54 | } 55 | } 56 | 57 | pub(crate) fn from_str(s: &str) -> Option> { 58 | match s { 59 | "x64" => Some(Box::new(x64::Archx64::default())), 60 | "x86" => Some(Box::new(x64::Archx86::default())), 61 | "aarch64" => Some(Box::new(aarch64::ArchAarch64::default())), 62 | "unknown" => Some(Box::new(DummyArch::new("unknown"))), 63 | _ => None 64 | } 65 | } 66 | 67 | #[cfg(target_arch="x86_64")] 68 | pub const CURRENT_ARCH: &str = "x64"; 69 | #[cfg(target_arch="x86")] 70 | pub const CURRENT_ARCH: &str = "x86"; 71 | #[cfg(target_arch="aarch64")] 72 | pub const CURRENT_ARCH: &str = "aarch64"; 73 | #[cfg(not(any(target_arch="x86", target_arch="x86_64", target_arch="aarch64")))] 74 | pub const CURRENT_ARCH: &str = "unknown"; 75 | -------------------------------------------------------------------------------- /doc/index.md: -------------------------------------------------------------------------------- 1 | % Dynasm-rs 2 | 3 | In the search for faster interpreters, Just-In-Time compilation is often a useful tool. 4 | This compiler extension attempts to make the writing of such programs easier and faster. 5 | 6 | At its core, dynasm-rs is an assembler compiler. It reads assembly templates which it then 7 | compiles into code that when executed will result in the proper machine code being emitted. 8 | 9 | Dynasm is split up into two parts. The first is the compiler extension that performs the 10 | translation of assembly templates into rust code, the second part is a 11 | [small runtime](../runtime/dynasmrt/index.html) that handles the generation of the wanted 12 | machine code. 13 | 14 | Dynasm-rs supports the x86, x64 and aarch64 instruction set architectures. 15 | 16 | Dynasm-rs is inspired by the LuaJIT DynASM project for C and C++. 17 | 18 | # Documentation 19 | 20 | The documentation of dynasm-rs is split up into several parts. To get started, you're advised 21 | to read through the [tutorial](./tutorial.html). After this, you can read through the 22 | [language reference](./langref_common.html) to learn about the syntax used by dynasm-rs. You can 23 | also read through the [runtime documentation](../runtime/dynasmrt/index.html) to learn about the 24 | runtime API. The instruction references lists all assembly mnemnonics 25 | and formats supported by dynasm-rs. Finally, documentation on the 26 | [internals on dynasm-rs](../plugin/dynasm/index.html) can be browsed here. 27 | 28 | # Differences from LuaJit Dynasm 29 | 30 | The following list summarizes some of the larger differences between LuaJIT dynasm and dynasm-rs. 31 | 32 | ## general 33 | 34 | - LuaJIT dynasm uses full program analysis, allowing it to compile local and global labels down to 35 | enums. Dynasm-rs however uses HashMaps keyed by static strings, meaning label resolution in dynasm-rs 36 | can be a bit slower. 37 | - LuaJIT local labels are integer literals. Dynasm-rs local labels are identifiers. 38 | - Dynasm-rs does not (directly) support stand-alone files. 39 | - LuaJIT dynasm uses a special preprocessor which detects lines starting with pipes (`|`) as dynasm 40 | instructions, dynasm-rs uses the `dynasm!` procedural macro with lines starting with semicolons (`;`). 41 | - LuaJIT has macros in its invocations, dynasm-rs uses rust macros that expand to `dynasm!` invocations. 42 | - Dynasm-rs doesn't have typed aliases 43 | 44 | ## x64/x86 45 | 46 | - LuaJIT uses the `mov64` mnemnonic to encode 64-bit displacement mov. Dynasm-rs uses the `movabs` 47 | mnemnonic with a 64-bit immediate parameter to encode this. 48 | - Dynasm-rs is not sensitive to the order of parameters inside a memory reference. 49 | - The syntax used for type maps is significantly different. In LuaJit dynasm it is `Type:reg->attr` 50 | in dynasm-rs it is `reg => Type.attr`. 51 | 52 | ## aarch64 53 | 54 | - Unknown. -------------------------------------------------------------------------------- /plugin/src/arch/aarch64/mod.rs: -------------------------------------------------------------------------------- 1 | use syn::parse; 2 | use proc_macro_error::emit_error; 3 | 4 | mod ast; 5 | mod parser; 6 | mod matching; 7 | mod compiler; 8 | mod aarch64data; 9 | mod encoding_helpers; 10 | mod debug; 11 | 12 | use crate::State; 13 | use crate::common::{Size, Stmt, Jump}; 14 | use crate::arch::Arch; 15 | use self::aarch64data::Relocation; 16 | 17 | #[cfg(feature = "dynasm_opmap")] 18 | pub use debug::create_opmap; 19 | #[cfg(feature = "dynasm_extract")] 20 | pub use debug::extract_opmap; 21 | 22 | struct Context<'a, 'b: 'a> { 23 | pub state: &'a mut State<'b> 24 | } 25 | 26 | #[derive(Clone, Debug)] 27 | pub struct ArchAarch64 { 28 | 29 | } 30 | 31 | impl Default for ArchAarch64 { 32 | fn default() -> ArchAarch64 { 33 | ArchAarch64 { } 34 | } 35 | } 36 | 37 | impl Arch for ArchAarch64 { 38 | fn name(&self) -> &str { 39 | "aarch64" 40 | } 41 | 42 | fn set_features(&mut self, features: &[syn::Ident]) { 43 | if let Some(feature) = features.first() { 44 | emit_error!(feature, "Arch aarch64 has no known features"); 45 | } 46 | } 47 | 48 | fn handle_static_reloc(&self, stmts: &mut Vec, reloc: Jump, size: Size) { 49 | let span = reloc.span(); 50 | 51 | let relocation = match size { 52 | Size::BYTE => Relocation::LITERAL8, 53 | Size::WORD => Relocation::LITERAL16, 54 | Size::DWORD => Relocation::LITERAL32, 55 | Size::QWORD => Relocation::LITERAL64, 56 | _ => { 57 | emit_error!(span, "Relocation of unsupported size for the current target architecture"); 58 | return; 59 | } 60 | }; 61 | 62 | stmts.push(Stmt::Const(0, size)); 63 | stmts.push(reloc.encode(size.in_bytes(), size.in_bytes(), &[relocation.to_id()])); 64 | } 65 | 66 | fn default_align(&self) -> u8 { 67 | 0 68 | } 69 | 70 | fn compile_instruction(&self, state: &mut State, input: parse::ParseStream) -> parse::Result<()> { 71 | let mut ctx = Context { 72 | state 73 | }; 74 | 75 | let (instruction, args) = parser::parse_instruction(&mut ctx, input)?; 76 | let span = instruction.span; 77 | 78 | let match_data = match matching::match_instruction(&mut ctx, &instruction, args) { 79 | Err(None) => return Ok(()), 80 | Err(Some(e)) => { 81 | emit_error!(span, e); 82 | return Ok(()) 83 | } 84 | Ok(m) => m 85 | }; 86 | 87 | match compiler::compile_instruction(&mut ctx, match_data) { 88 | Err(None) => return Ok(()), 89 | Err(Some(e)) => { 90 | emit_error!(span, e); 91 | return Ok(()) 92 | } 93 | Ok(()) => () 94 | } 95 | 96 | Ok(()) 97 | } 98 | } -------------------------------------------------------------------------------- /testing/tests/bugreports.rs: -------------------------------------------------------------------------------- 1 | #![allow(unused_imports)] 2 | 3 | use dynasmrt::dynasm; 4 | use dynasmrt::DynasmApi; 5 | 6 | // basic dynamic register usage 7 | #[test] 8 | fn bugreport_1() { 9 | let mut ops = dynasmrt::x64::Assembler::new().unwrap(); 10 | dynasm!(ops 11 | ; .arch x64 12 | ; int 3 13 | ; mov Rq(8), rdi 14 | ; add Rq(8), 1 15 | ; mov rax, Rq(8) 16 | ; ret 17 | ); 18 | let buf = ops.finalize().unwrap(); 19 | let hex: Vec = buf.iter().map(|x| format!("0x{:02X}", *x)).collect(); 20 | let hex: String = hex.join(", "); 21 | assert_eq!(hex, "0xCD, 0x03, 0x49, 0x89, 0xF8, 0x49, 0x83, 0xC0, 0x01, 0x4C, 0x89, 0xC0, 0xC3", "bugreport_1"); 22 | } 23 | 24 | // ensure RBP/RSP can be used as dynamic base register by always emitting the full SIB byte and a displacement 25 | #[test] 26 | fn bugreport_2() { 27 | let mut ops = dynasmrt::x64::Assembler::new().unwrap(); 28 | dynasm!(ops 29 | ; .arch x64 30 | ; inc [rsp] 31 | ; inc [Rq(4)] 32 | ; inc [Rq(4) + 1] 33 | ; inc [4 * rdx + Rq(4) + 1] 34 | ; inc [rbp] 35 | ; inc [Rq(5)] 36 | ; inc [Rq(5) + 1] 37 | ; inc [4 * rdx + Rq(5) + 1] 38 | ; inc [r12] 39 | ; inc [Rq(12)] 40 | ; inc [Rq(12) + 1] 41 | ; inc [4 * rdx + Rq(12) + 1] 42 | ; inc [r13] 43 | ; inc [Rq(13)] 44 | ; inc [Rq(13) + 1] 45 | ; inc [4 * rdx + Rq(13) + 1] 46 | ; inc [rcx] 47 | ; inc [Rq(1)] 48 | ; inc [Rq(1) + 1] 49 | ; inc [4 * rdx + Rq(1) + 1] 50 | ); 51 | let buf = ops.finalize().unwrap(); 52 | let hex: Vec = buf.iter().map(|x| format!("0x{:02X}", *x)).collect(); 53 | let hex: String = hex.join(", "); 54 | assert_eq!(hex, "0xFE, 0x04, 0x24, 0x40, 0xFE, 0x44, 0x24, 0x00, 0x40, 0xFE, 0x44, 0x24, 0x01, 0x40, 0xFE, 0x44, 0x94, 0x01, 0xFE, 0x45, 0x00, 0x40, 0xFE, 0x44, 0x25, 0x00, 0x40, 0xFE, 0x44, 0x25, 0x01, 0x40, 0xFE, 0x44, 0x95, 0x01, 0x41, 0xFE, 0x04, 0x24, 0x41, 0xFE, 0x44, 0x24, 0x00, 0x41, 0xFE, 0x44, 0x24, 0x01, 0x41, 0xFE, 0x44, 0x94, 0x01, 0x41, 0xFE, 0x45, 0x00, 0x41, 0xFE, 0x44, 0x25, 0x00, 0x41, 0xFE, 0x44, 0x25, 0x01, 0x41, 0xFE, 0x44, 0x95, 0x01, 0xFE, 0x01, 0x40, 0xFE, 0x44, 0x21, 0x00, 0x40, 0xFE, 0x44, 0x21, 0x01, 0x40, 0xFE, 0x44, 0x91, 0x01", "bugreport_2"); 55 | } 56 | 57 | // ensure dynamic registers work correctly with VEX ops 58 | #[test] 59 | fn bugreport_3() { 60 | let mut ops = dynasmrt::x64::Assembler::new().unwrap(); 61 | dynasm!(ops 62 | ; .arch x64 63 | ; vaddsd Rx(1), Rx(2), Rx(3) 64 | ; vaddsd Rx(10), Rx(9), Rx(11) 65 | ); 66 | let buf = ops.finalize().unwrap(); 67 | let hex: Vec = buf.iter().map(|x| format!("0x{:02X}", *x)).collect(); 68 | let hex: String = hex.join(", "); 69 | assert_eq!(hex, "0xC4, 0xE1, 0x6B, 0x58, 0xCB, 0xC4, 0x41, 0x33, 0x58, 0xD3", "bugreport_3"); 70 | } 71 | -------------------------------------------------------------------------------- /testing/tests/gen_x64/rtm.rs.gen: -------------------------------------------------------------------------------- 1 | 2 | #[test] 3 | fn enc_rtm_xabort5901() { 4 | let mut ops = dynasmrt::SimpleAssembler::new(); 5 | dynasm!(ops 6 | ; .arch x64 7 | ; xabort 30 8 | ); 9 | let buf = ops.finalize(); 10 | let hex: Vec = buf.iter().map(|x| format!("0x{:02X}", *x)).collect(); 11 | let hex: String = hex.join(", "); 12 | assert_eq!(hex, "0xC6, 0xF8, 0x1E", "xabort 30"); 13 | } 14 | 15 | 16 | 17 | #[test] 18 | fn enc_rtm_xabort5902() { 19 | let mut ops = dynasmrt::SimpleAssembler::new(); 20 | dynasm!(ops 21 | ; .arch x64 22 | ; xabort 118 23 | ); 24 | let buf = ops.finalize(); 25 | let hex: Vec = buf.iter().map(|x| format!("0x{:02X}", *x)).collect(); 26 | let hex: String = hex.join(", "); 27 | assert_eq!(hex, "0xC6, 0xF8, 0x76", "xabort 118"); 28 | } 29 | 30 | 31 | 32 | #[test] 33 | fn enc_rtm_xabort5903() { 34 | let mut ops = dynasmrt::SimpleAssembler::new(); 35 | dynasm!(ops 36 | ; .arch x64 37 | ; xabort 114 38 | ); 39 | let buf = ops.finalize(); 40 | let hex: Vec = buf.iter().map(|x| format!("0x{:02X}", *x)).collect(); 41 | let hex: String = hex.join(", "); 42 | assert_eq!(hex, "0xC6, 0xF8, 0x72", "xabort 114"); 43 | } 44 | 45 | 46 | 47 | #[test] 48 | fn enc_rtm_xabort5904() { 49 | let mut ops = dynasmrt::SimpleAssembler::new(); 50 | dynasm!(ops 51 | ; .arch x64 52 | ; xabort 29 53 | ); 54 | let buf = ops.finalize(); 55 | let hex: Vec = buf.iter().map(|x| format!("0x{:02X}", *x)).collect(); 56 | let hex: String = hex.join(", "); 57 | assert_eq!(hex, "0xC6, 0xF8, 0x1D", "xabort 29"); 58 | } 59 | 60 | 61 | 62 | #[test] 63 | fn enc_rtm_xabort5905() { 64 | let mut ops = dynasmrt::SimpleAssembler::new(); 65 | dynasm!(ops 66 | ; .arch x64 67 | ; xabort 48 68 | ); 69 | let buf = ops.finalize(); 70 | let hex: Vec = buf.iter().map(|x| format!("0x{:02X}", *x)).collect(); 71 | let hex: String = hex.join(", "); 72 | assert_eq!(hex, "0xC6, 0xF8, 0x30", "xabort 48"); 73 | } 74 | 75 | 76 | 77 | #[test] 78 | fn enc_rtm_xend5906() { 79 | let mut ops = dynasmrt::SimpleAssembler::new(); 80 | dynasm!(ops 81 | ; .arch x64 82 | ; xend 83 | ); 84 | let buf = ops.finalize(); 85 | let hex: Vec = buf.iter().map(|x| format!("0x{:02X}", *x)).collect(); 86 | let hex: String = hex.join(", "); 87 | assert_eq!(hex, "0x0F, 0x01, 0xD5", "xend"); 88 | } 89 | 90 | 91 | 92 | #[test] 93 | fn enc_rtm_xtest5907() { 94 | let mut ops = dynasmrt::SimpleAssembler::new(); 95 | dynasm!(ops 96 | ; .arch x64 97 | ; xtest 98 | ); 99 | let buf = ops.finalize(); 100 | let hex: Vec = buf.iter().map(|x| format!("0x{:02X}", *x)).collect(); 101 | let hex: String = hex.join(", "); 102 | assert_eq!(hex, "0x0F, 0x01, 0xD6", "xtest"); 103 | } 104 | 105 | 106 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # A Dynamic assembler written in Rust for Rust. 2 | 3 | The purpose of this tool is to ease the creation of programs that require run-time assembling. 4 | 5 | It is compatible with stable rustc 1.45 and higher. 6 | 7 | [![Build Status](https://travis-ci.org/CensoredUsername/dynasm-rs.svg?branch=master)](https://travis-ci.org/CensoredUsername/dynasm-rs) 8 | [![](https://img.shields.io/crates/v/dynasm.svg)](https://crates.io/crates/dynasm) 9 | 10 | `##dynasm-rs` on irc.libera.chat 11 | 12 | ## Features 13 | 14 | - Fully integrated in the rust toolchain, no other tools necessary. 15 | - The assembly is optimized into a series of `Vec.push` and `Vec.extend` statements. 16 | - Errors are almost all diagnosed at compile time in a clear fashion. 17 | - Write the to be generated assembly inline in nasm-like syntax using a simple macro. 18 | 19 | ## Documentation 20 | 21 | [Documentation](https://CensoredUsername.github.io/dynasm-rs/language/index.html). 22 | [Release notes](https://github.com/CensoredUsername/dynasm-rs/blob/master/doc/releasenotes.md). 23 | 24 | ## Architecture support 25 | 26 | - Supports the x64/x86 instruction sets in long and protected mode with every AMD/Intel/VIA extension except for AVX-512. 27 | - Supports the aarch64 instruction set up to ARMv8.4 except for SVE instructions. The development of this assembler backend has been generously sponsored by the awesome folks at [Wasmer](https://github.com/wasmerio/wasmer)! 28 | 29 | ## Example 30 | 31 | ```rust 32 | use dynasmrt::{dynasm, DynasmApi, DynasmLabelApi}; 33 | 34 | use std::{io, slice, mem}; 35 | use std::io::Write; 36 | 37 | fn main() { 38 | let mut ops = dynasmrt::x64::Assembler::new().unwrap(); 39 | let string = "Hello World!"; 40 | 41 | dynasm!(ops 42 | ; .arch x64 43 | ; ->hello: 44 | ; .bytes string.as_bytes() 45 | ); 46 | 47 | let hello = ops.offset(); 48 | dynasm!(ops 49 | ; .arch x64 50 | ; lea rcx, [->hello] 51 | ; xor edx, edx 52 | ; mov dl, BYTE string.len() as _ 53 | ; mov rax, QWORD print as _ 54 | ; sub rsp, BYTE 0x28 55 | ; call rax 56 | ; add rsp, BYTE 0x28 57 | ; ret 58 | ); 59 | 60 | let buf = ops.finalize().unwrap(); 61 | 62 | let hello_fn: extern "win64" fn() -> bool = unsafe { mem::transmute(buf.ptr(hello)) }; 63 | 64 | assert!(hello_fn()); 65 | } 66 | 67 | pub extern "win64" fn print(buffer: *const u8, length: u64) -> bool { 68 | io::stdout() 69 | .write_all(unsafe { slice::from_raw_parts(buffer, length as usize) }) 70 | .is_ok() 71 | } 72 | ``` 73 | 74 | ## Background 75 | 76 | This project is heavily inspired by [Dynasm](http://luajit.org/dynasm.html) 77 | 78 | ## Sponsorship 79 | 80 | The development of the Aarch64 assembler backend has been sponsored by [Wasmer](https://github.com/wasmerio/wasmer). 81 | 82 | ## License 83 | 84 | Mozilla Public License, v. 2.0, see LICENSE 85 | 86 | Copyright 2016 CensoredUsername 87 | 88 | ## Guaranteed to be working compiler versions 89 | 90 | This project used to be a compiler plugin, so for old compilers, here's a list of which version of dynasm was guaranteed to work with which compiler. 91 | As the project has since transitioned to be a proc macro, this is not relevant for modern versions of the compiler. 92 | 93 | - `v0.2.0`: `rustc 1.27.0-nightly (ac3c2288f 2018-04-18)` 94 | - `v0.2.1`: `rustc 1.28.0-nightly (a1d4a9503 2018-05-20)` 95 | - `v0.2.3`: `rustc 1.31.0-nightly (96cafc53c 2018-10-09)` 96 | -------------------------------------------------------------------------------- /plugin/src/arch/aarch64/encoding_helpers.rs: -------------------------------------------------------------------------------- 1 | use crate::common::{bitmask, bitmask64}; 2 | 3 | pub fn encode_floating_point_immediate(value: f32) -> Option { 4 | // floating point ARM immediates are encoded as 5 | // abcdefgh => aBbbbbbc defgh000 00000000 00000000 6 | // where B = !b 7 | // which means we can just slice out "a" and "bcdefgh" and assume the rest was correct 8 | 9 | let bits = value.to_bits(); 10 | 11 | let check = (bits >> 25) & 0x3F; 12 | if (check == 0b10_0000 || check == 0b01_1111) && (bits & 0x7_FFFF) == 0 { 13 | Some((((bits >> 24) & 0x80) | ((bits >> 19) & 0x7F)) as u8) 14 | } else { 15 | None 16 | } 17 | } 18 | 19 | pub fn encode_logical_immediate_32bit(value: u32) -> Option { 20 | let transitions = value ^ value.rotate_right(1); 21 | let element_size = (64u32).checked_div(transitions.count_ones())?; 22 | 23 | // confirm that the elements are identical 24 | if value != value.rotate_left(element_size) { 25 | return None; 26 | } 27 | 28 | let element = value & bitmask(element_size as u8); 29 | let ones = element.count_ones(); 30 | let imms = (!((element_size << 1) - 1) & 0x3F) | (ones - 1); 31 | 32 | let immr = if (element & 1) != 0 { 33 | ones - (!element).trailing_zeros() 34 | } else { 35 | element_size - element.trailing_zeros() 36 | }; 37 | 38 | Some(((immr as u16) << 6) | (imms as u16)) 39 | } 40 | 41 | pub fn encode_logical_immediate_64bit(value: u64) -> Option { 42 | let transitions = value ^ value.rotate_right(1); 43 | let element_size = (128u32).checked_div(transitions.count_ones())?; 44 | 45 | // confirm that the elements are identical 46 | if value != value.rotate_left(element_size) { 47 | return None; 48 | } 49 | 50 | let element = value & bitmask64(element_size as u8); 51 | let ones = element.count_ones(); 52 | let imms = (!((element_size << 1) - 1) & 0x7F) | (ones - 1); 53 | 54 | let immr = if (element & 1) != 0 { 55 | ones - (!element).trailing_zeros() 56 | } else { 57 | element_size - element.trailing_zeros() 58 | }; 59 | 60 | let n = imms & 0x40 == 0; 61 | let imms = imms & 0x3F; 62 | 63 | Some(((n as u16) << 12) | ((immr as u16) << 6) | (imms as u16)) 64 | } 65 | 66 | pub fn encode_stretched_immediate(value: u64) -> Option { 67 | // ensure the number is formatted correctly 68 | let mut test = value & 0x0101_0101_0101_0101; 69 | test |= test << 1; 70 | test |= test << 2; 71 | test |= test << 4; 72 | if test != value { 73 | return None; 74 | } 75 | 76 | // do bitwise magic 77 | let mut masked = value & 0x8040_2010_0804_0201; 78 | masked |= masked >> 32; 79 | masked |= masked >> 16; 80 | masked |= masked >> 8; 81 | let masked = masked as u32; 82 | Some(masked & 0xFF) 83 | } 84 | 85 | pub fn encode_wide_immediate_64bit(value: u64) -> Option { 86 | let offset = value.trailing_zeros() & 0b11_0000; 87 | let masked = 0xFFFF & (value >> offset); 88 | if (masked << offset) == value { 89 | Some((masked as u32) | (offset << 12)) 90 | } else { 91 | None 92 | } 93 | } 94 | 95 | pub fn encode_wide_immediate_32bit(value: u32) -> Option { 96 | let offset = value.trailing_zeros() & 0b1_0000; 97 | let masked = 0xFFFF & (value >> offset); 98 | if (masked << offset) == value { 99 | Some((masked as u32) | (offset << 12)) 100 | } else { 101 | None 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /tools/aarch64_data/tl_system.py: -------------------------------------------------------------------------------- 1 | 2 | tlentry(['AUTIA1716', 'AUTIASP', 'AUTIAZ', 'AUTIB1716', 'AUTIBSP', 'AUTIBZ', 'CFINV', 'CSDB', 'DRPS', 'ERET', 'ESB', 'NOP', 'PACIA1716', 'PACIASP', 'PACIAZ', 'PACIB1716', 'PACIBSP', 'PACIBZ', 'PSSBB', 'SB', 'SEV', 'SEVL', 'SSBB', 'WFE', 'WFI', 'XPACLRI', 'YIELD'], 3 | '', (), 4 | matcher = '', 5 | processor = '', 6 | ) 7 | 8 | tlentry(['HINT'], 9 | '#', (('CRm', 4, 8), ('op2', 3, 5)), 10 | matcher = 'Imm', 11 | processor = 'Ubits(5, 7)', 12 | ) 13 | 14 | tlentry(['BRK', 'HLT', 'HVC', 'SMC', 'SVC'], 15 | '#', (('imm16', 16, 5),), 16 | matcher = 'Imm', 17 | processor = 'Ubits(5, 16)', 18 | ) 19 | 20 | tlentry(['SYS'], 21 | '#,,,#{,}', (('op1', 3, 16), ('CRn', 4, 12), ('CRm', 4, 8), ('op2', 3, 5), ('Rt', 5, 0)), 22 | matcher = 'Imm, Ident, Ident, Imm, End, X', 23 | processor = 'Ubits(16, 3), LitList(12, "CONTROL_REGS"), LitList(8, "CONTROL_REGS"), Ubits(5, 3), R(0)', 24 | ) 25 | 26 | tlentry(['MSR'], 27 | '(|S____),', (('o0', 1, 19), ('op1', 3, 16), ('CRn', 4, 12), ('CRm', 4, 8), ('op2', 3, 5), ('Rt', 5, 0)), 28 | matcher = 'Imm, X', 29 | processor = 'Ubits(5, 15), R(0)', 30 | ) 31 | 32 | tlentry(['SYSL'], 33 | ',#,,,#', (('op1', 3, 16), ('CRn', 4, 12), ('CRm', 4, 8), ('op2', 3, 5), ('Rt', 5, 0)), 34 | matcher = 'X, Imm, Ident, Ident, Imm', 35 | processor = 'R(0), Ubits(16, 3), LitList(12, "CONTROL_REGS"), LitList(8, "CONTROL_REGS"), Ubits(5, 3)', 36 | ) 37 | 38 | tlentry(['MRS'], 39 | ',(|S____)', (('o0', 1, 19), ('op1', 3, 16), ('CRn', 4, 12), ('CRm', 4, 8), ('op2', 3, 5), ('Rt', 5, 0)), 40 | matcher = 'X, Imm', 41 | processor = 'R(0), Ubits(5, 15)', 42 | ) 43 | 44 | tlentry(['AT'], 45 | ',', (('op1', 3, 16), ('op2', 3, 5), ('Rt', 5, 0)), 46 | matcher = 'Ident, X', 47 | processor = 'LitList(5, "AT_OPS"), R(0)', 48 | ) 49 | 50 | tlentry(['DC'], 51 | ',', (('op1', 3, 16), ('CRm', 4, 8), ('op2', 3, 5), ('Rt', 5, 0)), 52 | matcher = 'Ident, X', 53 | processor = 'LitList(5, "DC_OPS"), R(0)', 54 | ) 55 | 56 | tlentry(['IC'], 57 | '{,}', (('op1', 3, 16), ('CRm', 4, 8), ('op2', 3, 5), ('Rt', 5, 0)), 58 | matcher = 'Lit("ivau"), X', 59 | processor = 'R(0), Static(5, 0b01101110101001)', 60 | matchers =['Ident'], 61 | processors=['LitList(5, "IC_OPS"), Static(0, 0b11111)'] 62 | ) 63 | 64 | tlentry(['DMB', 'DSB'], 65 | '