Squashed assembler

This commit is contained in:
Erin 2023-10-28 03:29:02 +02:00
parent 6e61842a73
commit ee20e06bb3
23 changed files with 863 additions and 664 deletions

363
Cargo.lock generated
View file

@ -18,12 +18,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
[[package]] [[package]]
name = "aho-corasick" name = "ahash"
version = "1.1.2" version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" checksum = "cd7d5a2cecb58716e47d67d5703a249964b14c7be1ec3cad3affc295b2d1c35d"
dependencies = [ dependencies = [
"memchr", "cfg-if",
"const-random",
"getrandom",
"once_cell",
"version_check",
"zerocopy",
] ]
[[package]] [[package]]
@ -84,16 +89,6 @@ version = "2.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" 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]] [[package]]
name = "cc" name = "cc"
version = "1.0.83" version = "1.0.83"
@ -137,21 +132,31 @@ dependencies = [
] ]
[[package]] [[package]]
name = "either" name = "const-random"
version = "1.9.0" version = "0.1.16"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" checksum = "11df32a13d7892ec42d51d3d175faba5211ffe13ed25d4fb348ac9e9ce835593"
dependencies = [
"const-random-macro",
]
[[package]] [[package]]
name = "errno" name = "const-random-macro"
version = "0.3.5" version = "0.1.16"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3e13f66a2f95e32a39eaa81f6b95d42878ca0e1db0c7543723dfe12557e860" checksum = "f9d839f2a20b0aee515dc581a6172f2321f96cab76c1a38a4c584a194955390e"
dependencies = [ dependencies = [
"libc", "getrandom",
"windows-sys", "once_cell",
"tiny-keccak",
] ]
[[package]]
name = "crunchy"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7"
[[package]] [[package]]
name = "eyre" name = "eyre"
version = "0.6.8" version = "0.6.8"
@ -162,6 +167,17 @@ dependencies = [
"once_cell", "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]] [[package]]
name = "gimli" name = "gimli"
version = "0.28.0" version = "0.28.0"
@ -172,8 +188,8 @@ checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0"
name = "hbasm" name = "hbasm"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"mlua",
"paste", "paste",
"rhai",
"with_builtin_macros", "with_builtin_macros",
] ]
@ -192,7 +208,7 @@ dependencies = [
] ]
[[package]] [[package]]
name = "hbxrt" name = "hbvm_aos_on_linux"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"hbvm", "hbvm",
@ -200,12 +216,11 @@ dependencies = [
] ]
[[package]] [[package]]
name = "home" name = "hbxrt"
version = "0.5.5" version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5444c27eef6923071f7ebcc33e3444508466a76f7a2b93da00ed6e19f30c1ddb"
dependencies = [ dependencies = [
"windows-sys", "hbvm",
"nix",
] ]
[[package]] [[package]]
@ -215,12 +230,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683" checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683"
[[package]] [[package]]
name = "itertools" name = "instant"
version = "0.11.0" version = "0.1.12"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c"
dependencies = [ dependencies = [
"either", "cfg-if",
] ]
[[package]] [[package]]
@ -235,31 +250,6 @@ version = "0.2.149"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a08173bc88b7955d1b3145aa561539096c421ac8debde8cbc3612ec635fee29b" 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]] [[package]]
name = "memchr" name = "memchr"
version = "2.6.4" version = "2.6.4"
@ -275,48 +265,6 @@ dependencies = [
"adler", "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]] [[package]]
name = "nix" name = "nix"
version = "0.27.1" version = "0.27.1"
@ -370,36 +318,6 @@ version = "0.2.13"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" 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]] [[package]]
name = "proc-macro2" name = "proc-macro2"
version = "1.0.69" version = "1.0.69"
@ -419,59 +337,38 @@ dependencies = [
] ]
[[package]] [[package]]
name = "regex" name = "rhai"
version = "1.10.2" version = "1.16.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343" checksum = "206cee941730eaf90a22c84235b25193df661393688162e15551164f92f09eca"
dependencies = [ dependencies = [
"aho-corasick", "ahash",
"memchr", "bitflags",
"regex-automata", "instant",
"regex-syntax", "num-traits",
"once_cell",
"rhai_codegen",
"smallvec",
"smartstring",
] ]
[[package]] [[package]]
name = "regex-automata" name = "rhai_codegen"
version = "0.4.3" version = "1.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f" checksum = "853977598f084a492323fe2f7896b4100a86284ee8473612de60021ea341310f"
dependencies = [ dependencies = [
"aho-corasick", "proc-macro2",
"memchr", "quote",
"regex-syntax", "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]] [[package]]
name = "rustc-demangle" name = "rustc-demangle"
version = "0.1.23" version = "0.1.23"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" 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]] [[package]]
name = "serde" name = "serde"
version = "1.0.189" version = "1.0.189"
@ -501,6 +398,29 @@ dependencies = [
"lazy_static", "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]] [[package]]
name = "syn" name = "syn"
version = "1.0.109" version = "1.0.109"
@ -533,6 +453,15 @@ dependencies = [
"once_cell", "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]] [[package]]
name = "tracing" name = "tracing"
version = "0.1.40" version = "0.1.40"
@ -593,82 +522,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
[[package]] [[package]]
name = "which" name = "wasi"
version = "4.4.2" version = "0.11.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
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"
[[package]] [[package]]
name = "with_builtin_macros" name = "with_builtin_macros"
@ -698,3 +555,23 @@ dependencies = [
"color-eyre", "color-eyre",
"once_cell", "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",
]

View file

@ -1,3 +1,3 @@
[workspace] [workspace]
resolver = "2" resolver = "2"
members = ["hbasm", "hbbytecode", "hbvm", "hbxrt", "xtask"] members = ["hbasm", "hbbytecode", "hbvm", "hbvm_aos_on_linux", "hbxrt", "xtask"]

View file

@ -5,8 +5,5 @@ edition = "2021"
[dependencies] [dependencies]
paste = "1.0" paste = "1.0"
rhai = "1.16"
with_builtin_macros = "0.0.3" with_builtin_macros = "0.0.3"
[dependencies.mlua]
version = "0.9"
features = ["luajit52", "macros", "vendored"]

View file

@ -1,3 +0,0 @@
li8(r1, 60)
li8(r2, 69)
eca()

View file

@ -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)

View file

@ -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();

View file

@ -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);}

View file

@ -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

View file

@ -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();
}

View file

@ -1,53 +0,0 @@
use mlua::prelude::*;
#[derive(Clone, Debug, Default, FromLua)]
pub struct ArrayList<T>(pub Vec<T>);
impl<T> LuaUserData for ArrayList<T>
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),
});
}
}

85
hbasm/src/data.rs Normal file
View file

@ -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<Self>) {
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::<DataRef>();
module
}

View file

@ -1,194 +1,226 @@
use { use {
crate::arraylist::ArrayList, crate::object::Object,
mlua::{prelude::*, Result, Scope}, rhai::{FnNamespace, Module},
std::{cell::RefCell, rc::Rc},
}; };
mod opsty { mod optypes {
pub type R = i8; use {
crate::{
label::UnboundLabel,
object::{Object, RelocKey, RelocType, SymbolRef},
},
rhai::{Dynamic, EvalAltResult, ImmutableString, Position},
};
pub type R = u8;
pub type B = i8; pub type B = i8;
pub type H = i16; pub type H = i16;
pub type W = i32; pub type W = i32;
pub type D = i64; 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 { pub type A = Dynamic;
($($plain:ident),* $(,)?) => { pub type O = Dynamic;
macro_rules! insert { pub type P = Dynamic;
$(
($label:expr, $lua:expr, $symrt:expr, $code:expr, $plain) => {
$code.0.extend($label.to_le_bytes());
};
)*
($label:expr, $lua:expr, $symrt:expr, $code:expr, O) => { pub fn insert_reloc(
insert_label_ref::<4>( obj: &mut Object,
$label, ty: RelocType,
$lua, val: &Dynamic,
&$symrt, ) -> Result<(), EvalAltResult> {
&mut $code.0, match () {
)?; _ if val.is::<SymbolRef>() => {
}; obj.relocation(RelocKey::Symbol(val.clone_cast::<SymbolRef>().0), ty)
($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::<ArrayList<u8>>()?;
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,
};
} }
_ if val.is::<UnboundLabel>() => {
writeln!( obj.relocation(RelocKey::Symbol(val.clone_cast::<UnboundLabel>().0), ty)
code, }
"function {name}(...) _GENERIC.{ty}({opcode}, ...) end", _ if val.is::<DataRef>() => {
ty = stringify!($ty).to_lowercase(), obj.relocation(RelocKey::Symbol(val.clone_cast::<DataRef>().symbol.0), ty)
opcode = $opcode, }
).unwrap(); _ if val.is_string() => {
obj.relocation(RelocKey::Label(val.clone_cast::<ImmutableString>()), ty)
})* }
_ if val.is_int() => {
lua.load(code).exec()?; let int = val.clone_cast::<i64>();
}}; 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()),
pub fn setup<'lua, 'scope>(lua: &'lua Lua, scope: &Scope<'lua, 'scope>) -> Result<()> RelocType::Abs64 => obj.sections.text.extend(int.to_le_bytes()),
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<const SIZE: usize>(
label: LuaValue,
lua: &Lua,
symrt: &LuaTable,
code: &mut Vec<u8>,
) -> 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})"
)));
} }
} }
.is_err() _ => {
{ return Err(EvalAltResult::ErrorMismatchDataType(
return Err(mlua::Error::runtime("Failed to cast offset")); "SybolRef, UnboundLabel, String or Int".to_owned(),
val.type_name().to_owned(),
Position::NONE,
))
} }
return Ok(());
} }
LuaValue::UserData(ud) => {
symrt.set( Ok(())
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(()) 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<A, B>(from: A) -> Result<B, EvalAltResult>
where
B: TryFrom<A>,
<B as TryFrom<A>>::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<RefCell<Object>>) {
with_builtin_macros::with_builtin! {
let $spec = include_from_root!("../hbbytecode/instructions.in") in {
instructions!((module, obj) { $spec });
}
}
} }

View file

@ -1,91 +1,76 @@
use { use {
crate::{arraylist::ArrayList, Labels}, crate::SharedObject,
mlua::{Result, prelude::*}, rhai::{Engine, ImmutableString, Module},
}; };
#[derive(Clone, Copy, Debug, PartialEq, Eq, FromLua)] #[derive(Clone, Copy, Debug)]
pub struct UnassignedLabel(pub usize); pub struct UnboundLabel(pub usize);
impl LuaUserData for UnassignedLabel {
fn add_fields<'lua, F: LuaUserDataFields<'lua, Self>>(fields: &mut F) { pub fn setup(engine: &mut Engine, module: &mut Module, object: SharedObject) {
fields.add_field_method_get("id", |_, this| Ok(this.0)); {
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, ()| { let object = SharedObject::clone(&object);
match lua let hash = module.set_native_fn("label", move |label: ImmutableString| {
.globals() let mut obj = object.borrow_mut();
.get::<_, LuaUserDataRefMut<Labels>>("_LABELS")? let symbol = obj.symbol(crate::object::Section::Text);
.0 obj.labels.insert(label, symbol.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<ArrayList<u8>>>("text")?
.0
.len(),
);
Ok(()) Ok(symbol)
} });
None => Err(mlua::Error::runtime("Invalid label")),
} 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(())
}); });
} }
}
engine.register_type_with_name::<UnboundLabel>("UnboundLabel");
#[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<LuaValue<'lua>> {
let globals = lua.globals();
let mut labels = globals.get::<_, LuaUserDataRefMut<Labels>>("_LABELS")?;
let code_ix = globals
.get::<_, LuaTable>("_CODE")?
.get::<_, LuaUserDataRefMut<ArrayList<u8>>>("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)",
)),
}),
}
} }

45
hbasm/src/lib.rs Normal file
View file

@ -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<RefCell<Object>>;
pub fn assembler(
linkout: &mut impl std::io::Write,
loader: impl FnOnce(&mut Engine) -> Result<(), Box<rhai::EvalAltResult>>,
) -> Result<(), Box<dyn std::error::Error>> {
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::<object::SymbolRef>("SymbolRef");
loader(&mut engine)?;
linker::link(obj, linkout)?;
Ok(())
}

View file

@ -1,44 +1,35 @@
use mlua::prelude::*; use {
crate::{
object::{RelocKey, RelocType, Section},
SharedObject,
},
std::io::Write,
};
pub fn link( pub fn link(object: SharedObject, out: &mut impl Write) -> std::io::Result<()> {
symrt: LuaTable, let obj = &mut *object.borrow_mut();
symtab: LuaTable, for (&loc, entry) in &obj.relocs {
labels: &[Option<usize>], let value = match &entry.key {
code: &mut [u8], RelocKey::Symbol(sym) => obj.symbols[*sym],
out: &mut impl std::io::Write, RelocKey::Label(label) => obj.symbols[obj.labels[label]],
) -> mlua::Result<()> { }
for item in symrt.pairs::<usize, LuaTable>() { .ok_or_else(|| std::io::Error::other("Invalid symbol"))?;
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"))?;
let loc = loc - 1; let offset = match value.location {
let dest = dest - 1; Section::Text => value.offset,
Section::Data => value.offset + obj.sections.text.len(),
let offset = dest.wrapping_sub(loc); };
match size {
4 => code[loc..loc + size].copy_from_slice(&(offset as u32).to_le_bytes()), match entry.ty {
2 => code[loc..loc + size].copy_from_slice(&(offset as u16).to_le_bytes()), RelocType::Rel32 => obj.sections.text[loc..loc + 4]
_ => return Err(mlua::Error::runtime("Invalid symbol")), .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(&obj.sections.text)?;
out.write_all(code)?; out.write_all(&obj.sections.data)
Ok(())
} }

View file

@ -1,54 +1,8 @@
mod arraylist; use std::{io::stdout, path::PathBuf};
mod ins;
mod label;
mod linker;
use {arraylist::ArrayList, mlua::{Result, prelude::*}, std::io::Read};
pub type Labels = ArrayList<Option<usize>>;
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::<u8>::default()),
("data", ArrayList::<u8>::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<ArrayList<u8>>>("text")?
.0,
&mut std::io::stdout(),
)
})?;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let path = PathBuf::from(std::env::args().nth(1).ok_or("Missing path")?);
hbasm::assembler(&mut stdout(), |engine| engine.run_file(path))?;
Ok(()) Ok(())
} }

77
hbasm/src/object.rs Normal file
View file

@ -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<u8>,
pub data: Vec<u8>,
}
#[derive(Clone, Debug, Default)]
pub struct Object {
pub sections: Sections,
pub symbols: Vec<Option<SymbolEntry>>,
pub labels: HashMap<ImmutableString, usize>,
pub relocs: HashMap<usize, RelocEntry>,
}
#[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],
});
}
}

View file

@ -34,11 +34,11 @@ define_items! {
OpsRRB (OpR, OpR, OpB ), OpsRRB (OpR, OpR, OpB ),
OpsRRH (OpR, OpR, OpH ), OpsRRH (OpR, OpR, OpH ),
OpsRRW (OpR, OpR, OpW ), OpsRRW (OpR, OpR, OpW ),
OpsRRD (OpR, OpR, OpD ),
OpsRB (OpR, OpB ), OpsRB (OpR, OpB ),
OpsRH (OpR, OpH ), OpsRH (OpR, OpH ),
OpsRW (OpR, OpW ), OpsRW (OpR, OpW ),
OpsRD (OpR, OpD ), OpsRD (OpR, OpD ),
OpsRRD (OpR, OpR, OpD ),
OpsRRA (OpR, OpR, OpA ), OpsRRA (OpR, OpR, OpA ),
OpsRRAH (OpR, OpR, OpA, OpH), OpsRRAH (OpR, OpR, OpA, OpH),
OpsRROH (OpR, OpR, OpO, OpH), OpsRROH (OpR, OpR, OpO, OpH),

View file

@ -273,6 +273,8 @@ where
let OpsRRP(a0, a1, ja) = self.decode(); let OpsRRP(a0, a1, ja) = self.decode();
if self.read_reg(a0).cast::<u64>() != self.read_reg(a1).cast::<u64>() { if self.read_reg(a0).cast::<u64>() != self.read_reg(a1).cast::<u64>() {
self.pc = self.pcrel(ja, 3); self.pc = self.pcrel(ja, 3);
} else {
self.bump_pc::<OpsRRP, true>();
} }
} }
JLTS => self.cond_jmp::<u64>(Ordering::Less), JLTS => self.cond_jmp::<u64>(Ordering::Less),
@ -453,7 +455,7 @@ where
let OpsRR(tg, reg) = self.decode(); let OpsRR(tg, reg) = self.decode();
let imm: T = self.decode(); let imm: T = self.decode();
self.write_reg(tg, op(self.read_reg(reg).cast::<T>(), imm)); self.write_reg(tg, op(self.read_reg(reg).cast::<T>(), imm));
self.bump_pc::<OpsRRD, false>(); self.bump_pc::<OpsRR, false>();
self.bump_pc::<T, true>(); self.bump_pc::<T, true>();
} }
@ -527,9 +529,9 @@ where
== expected == expected
{ {
self.pc = self.pcrel(ja, 3); self.pc = self.pcrel(ja, 3);
} else {
self.bump_pc::<OpsRRP, true>();
} }
self.bump_pc::<OpsRRP, true>();
} }
/// Read register /// Read register

View file

@ -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"] }

View file

@ -0,0 +1,3 @@
As close to the AbleOS runtime as possible
useful for me to spec out things on my laptop

View file

@ -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<dyn std::error::Error>> {
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(())
}

View file

@ -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<T: Copy>(&mut self, addr: Address) -> T {
core::ptr::read(addr.get() as *const T)
}
}