diff --git a/Cargo.lock b/Cargo.lock index ab773b4..d6b4d51 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -18,12 +18,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" [[package]] -name = "aho-corasick" -version = "1.1.2" +name = "ahash" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" +checksum = "cd7d5a2cecb58716e47d67d5703a249964b14c7be1ec3cad3affc295b2d1c35d" dependencies = [ - "memchr", + "cfg-if", + "const-random", + "getrandom", + "once_cell", + "version_check", + "zerocopy", ] [[package]] @@ -84,16 +89,6 @@ version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" -[[package]] -name = "bstr" -version = "1.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c79ad7fb2dd38f3dabd76b09c6a5a20c038fc0213ef1e9afd30eb777f120f019" -dependencies = [ - "memchr", - "serde", -] - [[package]] name = "cc" version = "1.0.83" @@ -137,21 +132,31 @@ dependencies = [ ] [[package]] -name = "either" -version = "1.9.0" +name = "const-random" +version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" +checksum = "11df32a13d7892ec42d51d3d175faba5211ffe13ed25d4fb348ac9e9ce835593" +dependencies = [ + "const-random-macro", +] [[package]] -name = "errno" -version = "0.3.5" +name = "const-random-macro" +version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3e13f66a2f95e32a39eaa81f6b95d42878ca0e1db0c7543723dfe12557e860" +checksum = "f9d839f2a20b0aee515dc581a6172f2321f96cab76c1a38a4c584a194955390e" dependencies = [ - "libc", - "windows-sys", + "getrandom", + "once_cell", + "tiny-keccak", ] +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + [[package]] name = "eyre" version = "0.6.8" @@ -162,6 +167,17 @@ dependencies = [ "once_cell", ] +[[package]] +name = "getrandom" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + [[package]] name = "gimli" version = "0.28.0" @@ -172,8 +188,8 @@ checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0" name = "hbasm" version = "0.1.0" dependencies = [ - "mlua", "paste", + "rhai", "with_builtin_macros", ] @@ -192,7 +208,7 @@ dependencies = [ ] [[package]] -name = "hbxrt" +name = "hbvm_aos_on_linux" version = "0.1.0" dependencies = [ "hbvm", @@ -200,12 +216,11 @@ dependencies = [ ] [[package]] -name = "home" -version = "0.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5444c27eef6923071f7ebcc33e3444508466a76f7a2b93da00ed6e19f30c1ddb" +name = "hbxrt" +version = "0.1.0" dependencies = [ - "windows-sys", + "hbvm", + "nix", ] [[package]] @@ -215,12 +230,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683" [[package]] -name = "itertools" -version = "0.11.0" +name = "instant" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" dependencies = [ - "either", + "cfg-if", ] [[package]] @@ -235,31 +250,6 @@ version = "0.2.149" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a08173bc88b7955d1b3145aa561539096c421ac8debde8cbc3612ec635fee29b" -[[package]] -name = "linux-raw-sys" -version = "0.4.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da2479e8c062e40bf0066ffa0bc823de0a9368974af99c9f6df941d2c231e03f" - -[[package]] -name = "lua-src" -version = "546.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c26d4af78361e025a3d03a2b964cd1592aff7495f4d4f7947218c084c6fdca8" -dependencies = [ - "cc", -] - -[[package]] -name = "luajit-src" -version = "210.4.8+resty107baaf" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e05167e8b2a2185758d83ed23541e5bd8bce37072e4204e0ef2c9b322bc87c4e" -dependencies = [ - "cc", - "which", -] - [[package]] name = "memchr" version = "2.6.4" @@ -275,48 +265,6 @@ dependencies = [ "adler", ] -[[package]] -name = "mlua" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c3a7a7ff4481ec91b951a733390211a8ace1caba57266ccb5f4d4966704e560" -dependencies = [ - "bstr", - "mlua-sys", - "mlua_derive", - "num-traits", - "once_cell", - "rustc-hash", -] - -[[package]] -name = "mlua-sys" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ec8b54eddb76093069cce9eeffb4c7b3a1a0fe66962d7bd44c4867928149ca3" -dependencies = [ - "cc", - "cfg-if", - "lua-src", - "luajit-src", - "pkg-config", -] - -[[package]] -name = "mlua_derive" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f359220f24e6452dd82a3f50d7242d4aab822b5594798048e953d7a9e0314c6" -dependencies = [ - "itertools", - "once_cell", - "proc-macro-error", - "proc-macro2", - "quote", - "regex", - "syn 2.0.38", -] - [[package]] name = "nix" version = "0.27.1" @@ -370,36 +318,6 @@ version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" -[[package]] -name = "pkg-config" -version = "0.3.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" - -[[package]] -name = "proc-macro-error" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" -dependencies = [ - "proc-macro-error-attr", - "proc-macro2", - "quote", - "syn 1.0.109", - "version_check", -] - -[[package]] -name = "proc-macro-error-attr" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" -dependencies = [ - "proc-macro2", - "quote", - "version_check", -] - [[package]] name = "proc-macro2" version = "1.0.69" @@ -419,59 +337,38 @@ dependencies = [ ] [[package]] -name = "regex" -version = "1.10.2" +name = "rhai" +version = "1.16.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343" +checksum = "206cee941730eaf90a22c84235b25193df661393688162e15551164f92f09eca" dependencies = [ - "aho-corasick", - "memchr", - "regex-automata", - "regex-syntax", + "ahash", + "bitflags", + "instant", + "num-traits", + "once_cell", + "rhai_codegen", + "smallvec", + "smartstring", ] [[package]] -name = "regex-automata" -version = "0.4.3" +name = "rhai_codegen" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f" +checksum = "853977598f084a492323fe2f7896b4100a86284ee8473612de60021ea341310f" dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", + "proc-macro2", + "quote", + "syn 2.0.38", ] -[[package]] -name = "regex-syntax" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" - [[package]] name = "rustc-demangle" version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" -[[package]] -name = "rustc-hash" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" - -[[package]] -name = "rustix" -version = "0.38.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67ce50cb2e16c2903e30d1cbccfd8387a74b9d4c938b6a4c5ec6cc7556f7a8a0" -dependencies = [ - "bitflags", - "errno", - "libc", - "linux-raw-sys", - "windows-sys", -] - [[package]] name = "serde" version = "1.0.189" @@ -501,6 +398,29 @@ dependencies = [ "lazy_static", ] +[[package]] +name = "smallvec" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "942b4a808e05215192e39f4ab80813e599068285906cc91aa64f923db842bd5a" + +[[package]] +name = "smartstring" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fb72c633efbaa2dd666986505016c32c3044395ceaf881518399d2f4127ee29" +dependencies = [ + "autocfg", + "static_assertions", + "version_check", +] + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + [[package]] name = "syn" version = "1.0.109" @@ -533,6 +453,15 @@ dependencies = [ "once_cell", ] +[[package]] +name = "tiny-keccak" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" +dependencies = [ + "crunchy", +] + [[package]] name = "tracing" version = "0.1.40" @@ -593,82 +522,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] -name = "which" -version = "4.4.2" +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" -dependencies = [ - "either", - "home", - "once_cell", - "rustix", -] - -[[package]] -name = "windows-sys" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" -dependencies = [ - "windows-targets", -] - -[[package]] -name = "windows-targets" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" -dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" - -[[package]] -name = "windows_i686_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" - -[[package]] -name = "windows_i686_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "with_builtin_macros" @@ -698,3 +555,23 @@ dependencies = [ "color-eyre", "once_cell", ] + +[[package]] +name = "zerocopy" +version = "0.7.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ffc046c9f849405a42c87e82e2f2f861d1f0a06b855910c76c2bd1e87be900c" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "246c000cfc5f942bac7ff99fde24a9ebb589d92e024bc758c6c733c15a02a73e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.38", +] diff --git a/Cargo.toml b/Cargo.toml index 91a11ba..02f5350 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,3 +1,3 @@ [workspace] resolver = "2" -members = ["hbasm", "hbbytecode", "hbvm", "hbxrt", "xtask"] +members = ["hbasm", "hbbytecode", "hbvm", "hbvm_aos_on_linux", "hbxrt", "xtask"] diff --git a/hbasm/Cargo.toml b/hbasm/Cargo.toml index 3fafd65..3cac566 100644 --- a/hbasm/Cargo.toml +++ b/hbasm/Cargo.toml @@ -5,8 +5,5 @@ edition = "2021" [dependencies] paste = "1.0" +rhai = "1.16" with_builtin_macros = "0.0.3" - -[dependencies.mlua] -version = "0.9" -features = ["luajit52", "macros", "vendored"] diff --git a/hbasm/assets/exit.lua b/hbasm/assets/exit.lua deleted file mode 100644 index e563181..0000000 --- a/hbasm/assets/exit.lua +++ /dev/null @@ -1,3 +0,0 @@ -li8(r1, 60) -li8(r2, 69) -eca() \ No newline at end of file diff --git a/hbasm/assets/label.lua b/hbasm/assets/label.lua deleted file mode 100644 index a88879f..0000000 --- a/hbasm/assets/label.lua +++ /dev/null @@ -1,8 +0,0 @@ -label "label" -- set named label -local a = label {} -- unassigned label - -jmp16("label") -a:here() -- assign label -jmp16(a) - -addi8(r3, r4, 5) \ No newline at end of file diff --git a/hbasm/examples/ableos/main.rhai b/hbasm/examples/ableos/main.rhai new file mode 100644 index 0000000..0302a2c --- /dev/null +++ b/hbasm/examples/ableos/main.rhai @@ -0,0 +1,13 @@ +import "hbasm/examples/ableos/std" as std; + +fn main(){ + std::Error(":+)"); + std::Warn("Your mom fell in a well!"); + std::Info("Hello, world!"); + std::Debug("ABC"); + std::Trace("Trace Deez"); + + tx(); +} + +main(); \ No newline at end of file diff --git a/hbasm/examples/ableos/std.rhai b/hbasm/examples/ableos/std.rhai new file mode 100644 index 0000000..5ff9dee --- /dev/null +++ b/hbasm/examples/ableos/std.rhai @@ -0,0 +1,24 @@ +fn ipc_send(buffer_id, mem_addr, length){ + // set the ecall + li8(r1, 3); + // Set the buffer ID to be the BufferID + li64(r2, buffer_id); + lra(r3, r0, mem_addr); + // set the length + li64(r4, length); + // ecall + eca(); +} + +private fn log(log_level, string){ + let str = data::str(string); + ipc_send(1, str, str.len); +} + +fn Error(string) {log(0, string);} +fn Warn(string) {log(1, string);} +fn Info(string) {log(2, string);} +// Due to rhai limitations this cannot be debug +// because of this all of the log levels are upper case +fn Debug(string) {log(3, string);} +fn Trace(string) {log(4, string);} diff --git a/hbasm/examples/hello-linux.rhai b/hbasm/examples/hello-linux.rhai new file mode 100644 index 0000000..326a80a --- /dev/null +++ b/hbasm/examples/hello-linux.rhai @@ -0,0 +1,9 @@ +let hello = data::str("Hello, world!"); + +li8 (r1, 1); // Write syscall +li8 (r2, 1); // Stdout FD +lra16 (r3, r0, hello); // String buffer +li8 (r4, hello.len); // String length +eca (); // System call + +tx (); // End program \ No newline at end of file diff --git a/hbasm/examples/macros.rhai b/hbasm/examples/macros.rhai new file mode 100644 index 0000000..afd7bd2 --- /dev/null +++ b/hbasm/examples/macros.rhai @@ -0,0 +1,33 @@ +li8(r1, 69); +li8(r2, 0); + +if_eq(r1, r2, + || puts("Equals!"), + || puts("Not equals!"), +); + + +tx(); // END OF MAIN + +/// Inline function – write text to stdout +fn puts(string) { + let d = data::str(string); + li8 (r1, 1); // Write syscall + li8 (r2, 1); // Stdout handle + lra16 (r3, r0, d); + li64 (r4, d.len); + eca (); +} + +fn if_eq(a, b, thenblk, elseblk) { + let elselbl = declabel(); + let endlbl = declabel(); + + jne(a, b, elselbl); + thenblk.call(); + jmp16(endlbl); + + elselbl.here(); + elseblk.call(); + endlbl.here(); +} \ No newline at end of file diff --git a/hbasm/src/arraylist.rs b/hbasm/src/arraylist.rs deleted file mode 100644 index 439984c..0000000 --- a/hbasm/src/arraylist.rs +++ /dev/null @@ -1,53 +0,0 @@ -use mlua::prelude::*; - -#[derive(Clone, Debug, Default, FromLua)] -pub struct ArrayList(pub Vec); -impl LuaUserData for ArrayList -where - T: for<'lua> FromLua<'lua> + for<'lua> IntoLua<'lua> + Clone + std::fmt::Debug, -{ - fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) { - methods.add_meta_method( - LuaMetaMethod::Index, - |lua, this, index: LuaInteger| match this.0.get( - (index as usize) - .checked_sub(1) - .ok_or_else(|| mlua::Error::runtime("Invalid index: 0"))?, - ) { - Some(i) => i.clone().into_lua(lua), - None => Ok(LuaValue::Nil), - }, - ); - - methods.add_meta_method_mut( - LuaMetaMethod::NewIndex, - |_, this, (index, val): (LuaInteger, T)| match this.0.get_mut( - (index as usize) - .checked_sub(1) - .ok_or_else(|| mlua::Error::runtime("Invalid index: 0"))?, - ) { - Some(x) => { - *x = val; - Ok(()) - } - None => Err(mlua::Error::runtime(format!( - "Index out of bounds: length = {}, index = {index}", - this.0.len() - ))), - }, - ); - - methods.add_meta_method(LuaMetaMethod::Len, |_, this, ()| Ok(this.0.len())); - methods.add_meta_method(LuaMetaMethod::ToString, |_, this, ()| { - Ok(format!("{this:?}")) - }); - methods.add_method_mut("push", |_, this, val: T| { - this.0.push(val); - Ok(()) - }); - methods.add_method_mut("pop", |lua, this, ()| match this.0.pop() { - Some(val) => val.into_lua(lua), - None => Ok(LuaValue::Nil), - }); - } -} diff --git a/hbasm/src/data.rs b/hbasm/src/data.rs new file mode 100644 index 0000000..a95c255 --- /dev/null +++ b/hbasm/src/data.rs @@ -0,0 +1,85 @@ +use rhai::{CustomType, Engine, ImmutableString}; + +use { + crate::{object::SymbolRef, SharedObject}, + rhai::Module, +}; + +macro_rules! gen_data_insertions { + ($module:expr, $obj:expr, [$($ty:ident),* $(,)?] $(,)?) => {{ + let (module, obj) = ($module, $obj); + $({ + let obj = ::std::rc::Rc::clone(obj); + let hash = module.set_native_fn(stringify!($ty), move |arr: ::rhai::Array| { + let obj = &mut *obj.borrow_mut(); + let symbol = obj.symbol($crate::object::Section::Data); + + obj.sections + .data + .reserve(arr.len() * ::std::mem::size_of::<$ty>()); + + for item in arr { + obj.sections.data.extend( + match item.as_int() { + Ok(num) => $ty::try_from(num).map_err(|_| "i64".to_owned()), + Err(ty) => Err(ty.to_owned()), + } + .map_err(|err| { + ::rhai::EvalAltResult::ErrorMismatchDataType( + stringify!($ty).to_owned(), + err, + ::rhai::Position::NONE, + ) + })? + .to_le_bytes(), + ); + } + + Ok(DataRef { + symbol, + len: obj.sections.data.len() - symbol.0, + }) + }); + + module.update_fn_namespace(hash, ::rhai::FnNamespace::Global); + })* + }}; +} + +#[derive(Clone, Copy, Debug)] +pub struct DataRef { + pub symbol: SymbolRef, + pub len: usize, +} + +impl CustomType for DataRef { + fn build(mut builder: rhai::TypeBuilder) { + builder + .with_name("DataRef") + .with_get("symbol", |this: &mut Self| this.symbol) + .with_get("len", |this: &mut Self| this.len as u64 as i64); + } +} + +pub fn module(engine: &mut Engine, obj: SharedObject) -> Module { + let mut module = Module::new(); + gen_data_insertions!(&mut module, &obj, [i8, i16, i32, i64]); + + { + let hash = module.set_native_fn("str", move |s: ImmutableString| { + let obj = &mut *obj.borrow_mut(); + let symbol = obj.symbol(crate::object::Section::Data); + + obj.sections.data.extend(s.as_bytes()); + Ok(DataRef { + symbol, + len: s.len(), + }) + }); + + module.update_fn_namespace(hash, rhai::FnNamespace::Global); + } + + engine.build_type::(); + module +} diff --git a/hbasm/src/ins.rs b/hbasm/src/ins.rs index f20bd18..590e23d 100644 --- a/hbasm/src/ins.rs +++ b/hbasm/src/ins.rs @@ -1,194 +1,226 @@ use { - crate::arraylist::ArrayList, - mlua::{prelude::*, Result, Scope}, + crate::object::Object, + rhai::{FnNamespace, Module}, + std::{cell::RefCell, rc::Rc}, }; -mod opsty { - pub type R = i8; +mod optypes { + use { + crate::{ + label::UnboundLabel, + object::{Object, RelocKey, RelocType, SymbolRef}, + }, + rhai::{Dynamic, EvalAltResult, ImmutableString, Position}, + }; + + pub type R = u8; pub type B = i8; pub type H = i16; pub type W = i32; pub type D = i64; - pub type A = i64; - pub type O<'lua> = super::LuaValue<'lua>; - pub type P<'lua> = super::LuaValue<'lua>; -} -macro_rules! gen_insert { - ($($plain:ident),* $(,)?) => { - macro_rules! insert { - $( - ($label:expr, $lua:expr, $symrt:expr, $code:expr, $plain) => { - $code.0.extend($label.to_le_bytes()); - }; - )* + pub type A = Dynamic; + pub type O = Dynamic; + pub type P = Dynamic; - ($label:expr, $lua:expr, $symrt:expr, $code:expr, O) => { - insert_label_ref::<4>( - $label, - $lua, - &$symrt, - &mut $code.0, - )?; - }; - - ($label:expr, $lua:expr, $symrt:expr, $code:expr, P) => { - insert_label_ref::<2>( - $label, - $lua, - &$symrt, - &mut $code.0, - )?; - }; - } - }; -} - -gen_insert!(R, B, H, W, D, A); - -macro_rules! generic_ins { - { - ($lua:expr, $scope:expr); - $($name:ident($($param_i:ident : $param_ty:ident),*);)* - } => {{ - let lua = $lua; - let scope = $scope; - - let code = $lua.globals() - .get::<_, LuaTable>("_CODE")? - .get::<_, LuaAnyUserData>("text")?; - - let symrt = $lua.globals() - .get::<_, LuaTable>("_SYM_REPLS")?; - - lua.globals().set( - "_GENERIC", - lua.create_table_from([$(( - stringify!($name), - #[allow(unused)] - { - let code = code.clone(); - let symrt = symrt.clone(); - scope.create_function_mut(move |lua, (opcode, $($param_i),*): (u8, $(opsty::$param_ty),*)| { - let mut code = code.borrow_mut::>()?; - code.0.push(opcode); - $(insert!($param_i, lua, symrt, code, $param_ty);)* - Ok(()) - })? - } - )),*])? - )?; - }}; -} - -macro_rules! ins { - { - $lua:expr; - {$($opcode:expr, $mnemonic:ident, $ty:ident, $_doc:literal;)*} - } => {{ - use std::fmt::Write; - - let lua = $lua; - let mut code = String::new(); - - $({ - paste::paste! { - let name = match stringify!([<$mnemonic:lower>]) { - "and" => "and_", - "or" => "or_", - "not" => "not_", - name => name, - }; + pub fn insert_reloc( + obj: &mut Object, + ty: RelocType, + val: &Dynamic, + ) -> Result<(), EvalAltResult> { + match () { + _ if val.is::() => { + obj.relocation(RelocKey::Symbol(val.clone_cast::().0), ty) } - - writeln!( - code, - "function {name}(...) _GENERIC.{ty}({opcode}, ...) end", - ty = stringify!($ty).to_lowercase(), - opcode = $opcode, - ).unwrap(); - - })* - - lua.load(code).exec()?; - }}; -} - -pub fn setup<'lua, 'scope>(lua: &'lua Lua, scope: &Scope<'lua, 'scope>) -> Result<()> -where - 'lua: 'scope, -{ - generic_ins! { - (lua, scope); - rr (o0: R, o1: R); - rrr (o0: R, o1: R, o2: R); - rrrr(o0: R, o1: R, o2: R, o3: R); - rrb (o0: R, o1: R, o2: B); - rrh (o0: R, o1: R, o2: H); - rrw (o0: R, o1: R, o2: W); - rrd (o0: R, o1: R, o2: D); - rb (o0: R, o1: B); - rh (o0: R, o1: H); - rw (o0: R, o1: W); - rd (o0: R, o1: D); - rrah(o0: R, o1: R, o2: A, o3: H); - rroh(o0: R, o1: R, o2: O, o3: H); - rrph(o0: R, o1: R, o2: P, o3: H); - rro (o0: R, o1: R, o2: O); - rrp (o0: R, o1: R, r2: P); - o (o0: O); - p (o0: P); - n (); - } - - with_builtin_macros::with_builtin! { - let $spec = include_from_root!("../hbbytecode/instructions.in") in { - ins!(lua; { $spec }); - } - } - - Ok(()) -} - -fn insert_label_ref( - label: LuaValue, - lua: &Lua, - symrt: &LuaTable, - code: &mut Vec, -) -> Result<()> { - match label { - LuaValue::Integer(offset) => { - if match SIZE { - 2 => i16::try_from(offset).map(|o| code.extend(o.to_le_bytes())), - 4 => i32::try_from(offset).map(|o| code.extend(o.to_le_bytes())), - s => { - return Err(mlua::Error::runtime(format!( - "Invalid offset size (expected 2 or 4 bytes, got {s})" - ))); + _ if val.is::() => { + obj.relocation(RelocKey::Symbol(val.clone_cast::().0), ty) + } + _ if val.is::() => { + obj.relocation(RelocKey::Symbol(val.clone_cast::().symbol.0), ty) + } + _ if val.is_string() => { + obj.relocation(RelocKey::Label(val.clone_cast::()), ty) + } + _ if val.is_int() => { + let int = val.clone_cast::(); + match ty { + RelocType::Rel32 => obj.sections.text.extend((int as i32).to_le_bytes()), + RelocType::Rel16 => obj.sections.text.extend((int as i16).to_le_bytes()), + RelocType::Abs64 => obj.sections.text.extend(int.to_le_bytes()), } } - .is_err() - { - return Err(mlua::Error::runtime("Failed to cast offset")); + _ => { + return Err(EvalAltResult::ErrorMismatchDataType( + "SybolRef, UnboundLabel, String or Int".to_owned(), + val.type_name().to_owned(), + Position::NONE, + )) } - return Ok(()); } - LuaValue::UserData(ud) => { - symrt.set( - code.len() + 1, - lua.create_table_from([("label", ud.get("id")?), ("size", SIZE)])?, - )?; - code.extend([0; SIZE]); - } - LuaValue::String(_) => { - symrt.set( - code.len() + 1, - lua.create_table_from([("label", label), ("size", SIZE.into_lua(lua)?)])?, - )?; - code.extend([0; SIZE]); - } - _ => return Err(mlua::Error::runtime("Invalid label type")), + + Ok(()) } - Ok(()) + macro_rules! gen_insert { + (le_bytes: [$($lety:ident),* $(,)?]) => { + macro_rules! insert { + $(($thing:expr, $obj: expr, $lety) => { + $obj.sections.text.extend($thing.to_le_bytes()); + };)* + + ($thing:expr, $obj:expr, A) => { + $crate::ins::optypes::insert_reloc( + $obj, + $crate::object::RelocType::Abs64, + $thing + )? + }; + ($thing:expr, $obj:expr, O) => { + $crate::ins::optypes::insert_reloc( + $obj, + $crate::object::RelocType::Rel32, + $thing + )? + }; + ($thing:expr, $obj:expr, P) => { + $crate::ins::optypes::insert_reloc( + $obj, + $crate::object::RelocType::Rel16, + $thing + )? + }; + } + }; + } + + gen_insert!(le_bytes: [R, B, H, W, D]); + + #[allow(clippy::single_component_path_imports)] + pub(super) use insert; + + use crate::data::DataRef; +} + +mod rity { + pub use super::optypes::{A, O, P, R}; + pub type B = i64; + pub type H = i64; + pub type W = i64; + pub type D = i64; +} + +mod generic { + use {crate::object::Object, rhai::EvalAltResult}; + + pub(super) fn convert_op(from: A) -> Result + where + B: TryFrom, + >::Error: std::error::Error + Sync + Send + 'static, + { + B::try_from(from).map_err(|e| { + EvalAltResult::ErrorSystem("Data conversion error".to_owned(), Box::new(e)) + }) + } + + macro_rules! gen_ins { + ($($($name:ident : $ty:ty),*;)*) => { + paste::paste! { + $(#[inline] + pub fn [<$($ty:lower)*>]( + obj: &mut Object, + opcode: u8, + $($name: $crate::ins::optypes::$ty),*, + ) -> Result<(), EvalAltResult> { + obj.sections.text.push(opcode); + $($crate::ins::optypes::insert!(&$name, obj, $ty);)* + Ok(()) + })* + + macro_rules! gen_ins_fn { + $(($obj:expr, $opcode:expr, [<$($ty)*>]) => { + move |$($name: $crate::ins::rity::$ty),*| { + $crate::ins::generic::[<$($ty:lower)*>]( + &mut *$obj.borrow_mut(), + $opcode, + $( + $crate::ins::generic::convert_op::< + _, + $crate::ins::optypes::$ty + >($name)? + ),* + )?; + Ok(()) + } + };)* + + ($obj:expr, $opcode:expr, N) => { + move || { + $crate::ins::generic::n(&mut *$obj.borrow_mut(), $opcode); + Ok(()) + } + }; + } + } + }; + } + + #[inline] + pub fn n(obj: &mut Object, opcode: u8) { + obj.sections.text.push(opcode); + } + + gen_ins! { + o0: R, o1: R; + o0: R, o1: R, o2: R; + o0: R, o1: R, o2: R, o3: R; + o0: R, o1: R, o2: B; + o0: R, o1: R, o2: H; + o0: R, o1: R, o2: W; + o0: R, o1: R, o2: D; + o0: R, o1: B; + o0: R, o1: H; + o0: R, o1: W; + o0: R, o1: D; + o0: R, o1: R, o2: A; + o0: R, o1: R, o2: A, o3: H; + o0: R, o1: R, o2: O, o3: H; + o0: R, o1: R, o2: P, o3: H; + o0: R, o1: R, o2: O; + o0: R, o1: R, o2: P; + o0: O; + o0: P; + } + + #[allow(clippy::single_component_path_imports)] + pub(super) use gen_ins_fn; +} + +macro_rules! instructions { + ( + ($module:expr, $obj:expr $(,)?) + { $($opcode:expr, $mnemonic:ident, $ops:ident, $doc:literal;)* } + ) => {{ + let (module, obj) = ($module, $obj); + $({ + let obj = Rc::clone(&obj); + let hash = module.set_native_fn( + paste::paste!(stringify!([<$mnemonic:lower>])), + generic::gen_ins_fn!( + obj, + $opcode, + $ops + ) + ); + + module.update_fn_namespace(hash, FnNamespace::Global); + })* + }}; +} + +pub fn setup(module: &mut Module, obj: Rc>) { + with_builtin_macros::with_builtin! { + let $spec = include_from_root!("../hbbytecode/instructions.in") in { + instructions!((module, obj) { $spec }); + } + } } diff --git a/hbasm/src/label.rs b/hbasm/src/label.rs index da0c1cd..d154737 100644 --- a/hbasm/src/label.rs +++ b/hbasm/src/label.rs @@ -1,91 +1,76 @@ use { - crate::{arraylist::ArrayList, Labels}, - mlua::{Result, prelude::*}, + crate::SharedObject, + rhai::{Engine, ImmutableString, Module}, }; -#[derive(Clone, Copy, Debug, PartialEq, Eq, FromLua)] -pub struct UnassignedLabel(pub usize); -impl LuaUserData for UnassignedLabel { - fn add_fields<'lua, F: LuaUserDataFields<'lua, Self>>(fields: &mut F) { - fields.add_field_method_get("id", |_, this| Ok(this.0)); +#[derive(Clone, Copy, Debug)] +pub struct UnboundLabel(pub usize); + +pub fn setup(engine: &mut Engine, module: &mut Module, object: SharedObject) { + { + let object = SharedObject::clone(&object); + let hash = module.set_native_fn("label", move || { + let mut obj = object.borrow_mut(); + let symbol = obj.symbol(crate::object::Section::Text); + Ok(symbol) + }); + + module.update_fn_namespace(hash, rhai::FnNamespace::Global); } - fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) { - methods.add_method("here", |lua, this, ()| { - match lua - .globals() - .get::<_, LuaUserDataRefMut>("_LABELS")? - .0 - .get_mut( - this.0 - .checked_sub(1) - .ok_or_else(|| mlua::Error::runtime("Invalid label"))?, - ) { - Some(entry) => { - *entry = Some( - lua.globals() - .get::<_, LuaTable>("_CODE")? - .get::<_, LuaUserDataRef>>("text")? - .0 - .len(), - ); + { + let object = SharedObject::clone(&object); + let hash = module.set_native_fn("label", move |label: ImmutableString| { + let mut obj = object.borrow_mut(); + let symbol = obj.symbol(crate::object::Section::Text); + obj.labels.insert(label, symbol.0); - Ok(()) - } - None => Err(mlua::Error::runtime("Invalid label")), - } + Ok(symbol) + }); + + module.update_fn_namespace(hash, rhai::FnNamespace::Global); + } + + { + let object = SharedObject::clone(&object); + let hash = module.set_native_fn("declabel", move || { + let mut obj = object.borrow_mut(); + + let index = obj.symbols.len(); + obj.symbols.push(None); + + Ok(UnboundLabel(index)) + }); + + module.update_fn_namespace(hash, rhai::FnNamespace::Global); + } + + { + let object = SharedObject::clone(&object); + let hash = module.set_native_fn("declabel", move |label: ImmutableString| { + let mut obj = object.borrow_mut(); + + let index = obj.symbols.len(); + obj.symbols.push(None); + obj.labels.insert(label, index); + + Ok(UnboundLabel(index)) + }); + + module.update_fn_namespace(hash, rhai::FnNamespace::Global); + } + + { + module.set_native_fn("here", move |label: UnboundLabel| { + let mut obj = object.borrow_mut(); + obj.symbols[label.0] = Some(crate::object::SymbolEntry { + location: crate::object::Section::Text, + offset: obj.sections.text.len(), + }); + + Ok(()) }); } -} - -#[derive(Clone, Copy, Debug, PartialEq, Eq, FromLua)] -pub struct Label(pub usize); -impl LuaUserData for Label { - fn add_fields<'lua, F: LuaUserDataFields<'lua, Self>>(fields: &mut F) { - fields.add_field_method_get("id", |_, this| Ok(this.0)); - } -} - -pub fn label<'lua>(lua: &'lua Lua, val: LuaValue<'lua>) -> Result> { - let globals = lua.globals(); - let mut labels = globals.get::<_, LuaUserDataRefMut>("_LABELS")?; - - let code_ix = globals - .get::<_, LuaTable>("_CODE")? - .get::<_, LuaUserDataRefMut>>("text")? - .0 - .len(); - - match val { - LuaValue::Table(_) => { - labels.0.push(None); - Ok(LuaValue::UserData( - lua.create_userdata(UnassignedLabel(labels.0.len()))?, - )) - } - LuaValue::String(str) => { - labels.0.push(Some(code_ix + 1)); - globals - .get::<_, LuaTable>("_SYM_TABLE")? - .set(str, labels.0.len())?; - - Ok(LuaValue::UserData( - lua.create_userdata(Label(labels.0.len()))?, - )) - } - LuaNil => { - labels.0.push(Some(code_ix + 1)); - Ok(LuaValue::UserData( - lua.create_userdata(Label(labels.0.len()))?, - )) - } - _ => Err(mlua::Error::BadArgument { - to: Some("label".into()), - pos: 1, - name: None, - cause: std::sync::Arc::new(mlua::Error::runtime( - "Unsupported type (nil and string are only supported)", - )), - }), - } + + engine.register_type_with_name::("UnboundLabel"); } diff --git a/hbasm/src/lib.rs b/hbasm/src/lib.rs new file mode 100644 index 0000000..c4a7c87 --- /dev/null +++ b/hbasm/src/lib.rs @@ -0,0 +1,45 @@ +mod data; +mod ins; +mod label; +mod linker; +mod object; + +use { + object::Object, + rhai::{Engine, Module}, + std::{cell::RefCell, rc::Rc}, +}; + +type SharedObject = Rc>; + +pub fn assembler( + linkout: &mut impl std::io::Write, + loader: impl FnOnce(&mut Engine) -> Result<(), Box>, +) -> Result<(), Box> { + let mut engine = Engine::new(); + let mut module = Module::new(); + let obj = Rc::new(RefCell::new(Object::default())); + ins::setup(&mut module, Rc::clone(&obj)); + label::setup(&mut engine, &mut module, Rc::clone(&obj)); + + // Registers + for n in 0_u8..255 { + module.set_var(format!("r{n}"), n); + } + + module.set_native_fn("reg", |n: i64| { + Ok(u8::try_from(n).map_err(|_| { + rhai::EvalAltResult::ErrorRuntime("Invalid register value".into(), rhai::Position::NONE) + })?) + }); + + module.set_native_fn("as_i64", |n: u8| Ok(n as i64)); + + let datamod = Rc::new(data::module(&mut engine, SharedObject::clone(&obj))); + engine.register_global_module(Rc::new(module)); + engine.register_static_module("data", datamod); + engine.register_type_with_name::("SymbolRef"); + loader(&mut engine)?; + linker::link(obj, linkout)?; + Ok(()) +} diff --git a/hbasm/src/linker.rs b/hbasm/src/linker.rs index 566c2df..d31c73b 100644 --- a/hbasm/src/linker.rs +++ b/hbasm/src/linker.rs @@ -1,44 +1,35 @@ -use mlua::prelude::*; +use { + crate::{ + object::{RelocKey, RelocType, Section}, + SharedObject, + }, + std::io::Write, +}; -pub fn link( - symrt: LuaTable, - symtab: LuaTable, - labels: &[Option], - code: &mut [u8], - out: &mut impl std::io::Write, -) -> mlua::Result<()> { - for item in symrt.pairs::() { - let (loc, val) = item?; - let size: usize = val.get("size")?; - let dest = labels - .get( - match val.get::<_, LuaValue>("label")? { - LuaValue::Integer(i) => i, - LuaValue::String(s) => symtab.get(s)?, - _ => { - return Err(mlua::Error::runtime( - "Invalid symbol type (int or string expected)", - )) - } - } as usize - - 1, - ) - .copied() - .flatten() - .ok_or_else(|| mlua::Error::runtime("Invalid label"))?; +pub fn link(object: SharedObject, out: &mut impl Write) -> std::io::Result<()> { + let obj = &mut *object.borrow_mut(); + for (&loc, entry) in &obj.relocs { + let value = match &entry.key { + RelocKey::Symbol(sym) => obj.symbols[*sym], + RelocKey::Label(label) => obj.symbols[obj.labels[label]], + } + .ok_or_else(|| std::io::Error::other("Invalid symbol"))?; - let loc = loc - 1; - let dest = dest - 1; - - let offset = dest.wrapping_sub(loc); - match size { - 4 => code[loc..loc + size].copy_from_slice(&(offset as u32).to_le_bytes()), - 2 => code[loc..loc + size].copy_from_slice(&(offset as u16).to_le_bytes()), - _ => return Err(mlua::Error::runtime("Invalid symbol")), + let offset = match value.location { + Section::Text => value.offset, + Section::Data => value.offset + obj.sections.text.len(), + }; + + match entry.ty { + RelocType::Rel32 => obj.sections.text[loc..loc + 4] + .copy_from_slice(&((offset as isize - loc as isize) as i32).to_le_bytes()), + RelocType::Rel16 => obj.sections.text[loc..loc + 2] + .copy_from_slice(&((offset as isize - loc as isize) as i16).to_le_bytes()), + RelocType::Abs64 => obj.sections.text[loc..loc + 8] + .copy_from_slice(&(offset as isize - loc as isize).to_le_bytes()), } } - dbg!(&code); - out.write_all(code)?; - Ok(()) + out.write_all(&obj.sections.text)?; + out.write_all(&obj.sections.data) } diff --git a/hbasm/src/main.rs b/hbasm/src/main.rs index a9a0f9a..ca9a258 100644 --- a/hbasm/src/main.rs +++ b/hbasm/src/main.rs @@ -1,54 +1,8 @@ -mod arraylist; -mod ins; -mod label; -mod linker; - -use {arraylist::ArrayList, mlua::{Result, prelude::*}, std::io::Read}; - -pub type Labels = ArrayList>; - -fn main() -> Result<()> { - let mut code = vec![]; - std::io::stdin().read_to_end(&mut code)?; - - let lua = Lua::new(); - lua.scope(|scope| { - // Global values - let globals = lua.globals(); - globals.set( - "_CODE", - lua.create_table_from([ - ("text", ArrayList::::default()), - ("data", ArrayList::::default()), - ])?, - )?; - - globals.set("_LABELS", Labels::default())?; - globals.set("_SYM_TABLE", lua.create_table()?)?; - globals.set("_SYM_REPLS", lua.create_table()?)?; - - // Functions - globals.set("label", lua.create_function(label::label)?)?; - ins::setup(&lua, scope)?; - - // Register symbols - for n in 0..255 { - globals.set(format!("r{n}"), n)?; - } - - lua.load(code).exec()?; - - linker::link( - globals.get("_SYM_REPLS")?, - globals.get("_SYM_TABLE")?, - &globals.get::<_, Labels>("_LABELS")?.0, - &mut globals - .get::<_, LuaTable>("_CODE")? - .get::<_, LuaUserDataRefMut>>("text")? - .0, - &mut std::io::stdout(), - ) - })?; +use std::{io::stdout, path::PathBuf}; +fn main() -> Result<(), Box> { + let path = PathBuf::from(std::env::args().nth(1).ok_or("Missing path")?); + hbasm::assembler(&mut stdout(), |engine| engine.run_file(path))?; + Ok(()) } diff --git a/hbasm/src/object.rs b/hbasm/src/object.rs new file mode 100644 index 0000000..bae43df --- /dev/null +++ b/hbasm/src/object.rs @@ -0,0 +1,77 @@ +use {rhai::ImmutableString, std::collections::HashMap}; + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum Section { + Text, + Data, +} + +#[derive(Clone, Copy, Debug)] +pub struct SymbolEntry { + pub location: Section, + pub offset: usize, +} + +#[derive(Clone, Debug)] +pub enum RelocKey { + Symbol(usize), + Label(ImmutableString), +} + +#[derive(Clone, Copy, Debug)] +pub enum RelocType { + Rel32, + Rel16, + Abs64, +} + +#[derive(Clone, Debug)] +pub struct RelocEntry { + pub key: RelocKey, + pub ty: RelocType, +} + +#[derive(Clone, Debug, Default)] +pub struct Sections { + pub text: Vec, + pub data: Vec, +} + +#[derive(Clone, Debug, Default)] +pub struct Object { + pub sections: Sections, + pub symbols: Vec>, + pub labels: HashMap, + pub relocs: HashMap, +} + +#[derive(Clone, Copy, Debug)] +#[repr(transparent)] +pub struct SymbolRef(pub usize); + +impl Object { + pub fn symbol(&mut self, section: Section) -> SymbolRef { + let section_buf = match section { + Section::Text => &mut self.sections.text, + Section::Data => &mut self.sections.data, + }; + + self.symbols.push(Some(SymbolEntry { + location: section, + offset: section_buf.len(), + })); + + SymbolRef(self.symbols.len() - 1) + } + + pub fn relocation(&mut self, key: RelocKey, ty: RelocType) { + self.relocs + .insert(self.sections.text.len(), RelocEntry { key, ty }); + + self.sections.text.extend(match ty { + RelocType::Rel32 => &[0_u8; 4] as &[u8], + RelocType::Rel16 => &[0; 2], + RelocType::Abs64 => &[0; 8], + }); + } +} diff --git a/hbbytecode/src/lib.rs b/hbbytecode/src/lib.rs index 4fe81ba..488ebe7 100644 --- a/hbbytecode/src/lib.rs +++ b/hbbytecode/src/lib.rs @@ -34,11 +34,11 @@ define_items! { OpsRRB (OpR, OpR, OpB ), OpsRRH (OpR, OpR, OpH ), OpsRRW (OpR, OpR, OpW ), + OpsRRD (OpR, OpR, OpD ), OpsRB (OpR, OpB ), OpsRH (OpR, OpH ), OpsRW (OpR, OpW ), OpsRD (OpR, OpD ), - OpsRRD (OpR, OpR, OpD ), OpsRRA (OpR, OpR, OpA ), OpsRRAH (OpR, OpR, OpA, OpH), OpsRROH (OpR, OpR, OpO, OpH), diff --git a/hbvm/src/vmrun.rs b/hbvm/src/vmrun.rs index debe423..fbf7f3d 100644 --- a/hbvm/src/vmrun.rs +++ b/hbvm/src/vmrun.rs @@ -273,6 +273,8 @@ where let OpsRRP(a0, a1, ja) = self.decode(); if self.read_reg(a0).cast::() != self.read_reg(a1).cast::() { self.pc = self.pcrel(ja, 3); + } else { + self.bump_pc::(); } } JLTS => self.cond_jmp::(Ordering::Less), @@ -453,7 +455,7 @@ where let OpsRR(tg, reg) = self.decode(); let imm: T = self.decode(); self.write_reg(tg, op(self.read_reg(reg).cast::(), imm)); - self.bump_pc::(); + self.bump_pc::(); self.bump_pc::(); } @@ -527,9 +529,9 @@ where == expected { self.pc = self.pcrel(ja, 3); + } else { + self.bump_pc::(); } - - self.bump_pc::(); } /// Read register diff --git a/hbvm_aos_on_linux/Cargo.toml b/hbvm_aos_on_linux/Cargo.toml new file mode 100644 index 0000000..a82122d --- /dev/null +++ b/hbvm_aos_on_linux/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "hbvm_aos_on_linux" +version = "0.1.0" +edition = "2021" +default-run = "hbvm_aos_on_linux" + +[dependencies] +hbvm.path = "../hbvm" +nix = { version = "0.27", features = ["mman", "signal"] } diff --git a/hbvm_aos_on_linux/readme.md b/hbvm_aos_on_linux/readme.md new file mode 100644 index 0000000..24d919f --- /dev/null +++ b/hbvm_aos_on_linux/readme.md @@ -0,0 +1,3 @@ +As close to the AbleOS runtime as possible + +useful for me to spec out things on my laptop \ No newline at end of file diff --git a/hbvm_aos_on_linux/src/main.rs b/hbvm_aos_on_linux/src/main.rs new file mode 100644 index 0000000..38dea08 --- /dev/null +++ b/hbvm_aos_on_linux/src/main.rs @@ -0,0 +1,96 @@ +//! Holey Bytes Experimental Runtime +mod mem; + +use { + hbvm::{mem::Address, Vm, VmRunOk}, + nix::sys::mman::{mmap, MapFlags, ProtFlags}, + std::{env::args, fs::File, num::NonZeroUsize, process::exit}, +}; + +fn main() -> Result<(), Box> { + eprintln!("== HB×RT (Holey Bytes Linux Runtime) v0.1 =="); + eprintln!("[W] Currently supporting only flat images"); + + let Some(image_path) = args().nth(1) else { + eprintln!("[E] Missing image path"); + exit(1); + }; + + // Load program + eprintln!("[I] Loading image from \"{image_path}\""); + let file = File::open(image_path)?; + let ptr = unsafe { + mmap( + None, + NonZeroUsize::new(file.metadata()?.len() as usize).ok_or("File is empty")?, + ProtFlags::PROT_READ, + MapFlags::MAP_PRIVATE, + Some(&file), + 0, + )? + }; + + eprintln!("[I] Image loaded at {ptr:p}"); + + // Execute program + let mut vm = unsafe { Vm::<_, 0>::new(mem::HostMemory, Address::new(ptr as u64)) }; + + // Memory access fault handling + unsafe { + use nix::sys::signal; + + extern "C" fn action( + _: std::ffi::c_int, + info: *mut nix::libc::siginfo_t, + _: *mut std::ffi::c_void, + ) { + unsafe { + eprintln!("[E] Memory access fault at {:p}", (*info).si_addr()); + } + } + + signal::sigaction( + signal::Signal::SIGSEGV, + &nix::sys::signal::SigAction::new( + signal::SigHandler::SigAction(action), + signal::SaFlags::SA_NODEFER, + nix::sys::signalfd::SigSet::empty(), + ), + )?; + } + + let stat = loop { + match vm.run() { + Ok(VmRunOk::Breakpoint) => eprintln!( + "[I] Hit breakpoint\nIP: {}\n== Registers ==\n{:?}", + vm.pc, vm.registers + ), + Ok(VmRunOk::Timer) => (), + Ok(VmRunOk::Ecall) => { + + // unsafe { + // std::arch::asm!( + // "syscall", + // inlateout("rax") vm.registers[1].0, + // in("rdi") vm.registers[2].0, + // in("rsi") vm.registers[3].0, + // in("rdx") vm.registers[4].0, + // in("r10") vm.registers[5].0, + // in("r8") vm.registers[6].0, + // in("r9") vm.registers[7].0, + // ) + // } + } + Ok(VmRunOk::End) => break Ok(()), + Err(e) => break Err(e), + } + }; + + eprintln!("\n== Registers ==\n{:?}", vm.registers); + if let Err(e) = stat { + eprintln!("\n[E] Runtime error: {e:?}"); + exit(2); + } + + Ok(()) +} diff --git a/hbvm_aos_on_linux/src/mem.rs b/hbvm_aos_on_linux/src/mem.rs new file mode 100644 index 0000000..e1687d3 --- /dev/null +++ b/hbvm_aos_on_linux/src/mem.rs @@ -0,0 +1,31 @@ +use hbvm::mem::{Address, LoadError, Memory, StoreError}; + +pub struct HostMemory; +impl Memory for HostMemory { + #[inline] + unsafe fn load( + &mut self, + addr: Address, + target: *mut u8, + count: usize, + ) -> Result<(), LoadError> { + unsafe { core::ptr::copy(addr.get() as *const u8, target, count) } + Ok(()) + } + + #[inline] + unsafe fn store( + &mut self, + addr: Address, + source: *const u8, + count: usize, + ) -> Result<(), StoreError> { + unsafe { core::ptr::copy(source, addr.get() as *mut u8, count) } + Ok(()) + } + + #[inline] + unsafe fn prog_read(&mut self, addr: Address) -> T { + core::ptr::read(addr.get() as *const T) + } +}