Embeddable OCaml and C toolkit for deterministic polymorphic bytecode execution. It's bytecode has a stable logical instruction set, while physical opcode numbers can be permuted across mutation epochs. Mutated programs keep the same observable behaviour and traces still show both the logical instruction and the physical opcode that reached it
make buildBuild/run the factorial
dune exec -- nala build examples/factorial.nala.asm -o examples/factorial.nala
dune exec -- nala verify examples/factorial.nala
dune exec -- nala run examples/factorial.nalaMutate the physical opcode mapping with a reproducible seed
dune exec -- nala mutate examples/factorial.nala --seed 42 -o examples/factorial.mut.nala
dune exec -- nala run examples/factorial.mut.nala
dune exec -- nala inspect examples/factorial.mut.nalaTrace the mutated package
dune exec -- nala trace examples/factorial.mut.nalapc=0000 epoch=43 physical=011 logical=const stack=[]->[6]
pc=0001 epoch=43 physical=019 logical=call stack=[6]->[]
nala build <source> -o program.nala
nala run program.nala
nala verify program.nala
nala disasm program.nala
nala mutate program.nala --seed <n> -o mutated.nala
nala trace program.nala
nala inspect program.nala
nala repl.meta name answer
.func main 0 0
const 40
const 2
add
out
haltFunctions declare argument count and local count
.func main 0 0
const 6
call fact
out
halt
.func fact 1 1
load 0
const 2
lt
jz recur
const 1
ret
recur:
load 0
load 0
const 1
sub
call fact
mul
retHost imports are explicit and arity checked
.import double 1
.func main 0 0
const 21
import double
out
haltlet fail diags =
List.iter (fun d -> prerr_endline (Nala.Verifier.pp_diagnostic d)) diags;
exit 1
let () =
match Nala.Assembler.assemble_file "examples/factorial.nala.asm" with
| Error e -> fail e
| Ok program ->
begin match Nala.Verifier.verify program with
| Error e -> fail e
| Ok () -> ()
end;
let mutated = Nala.Mutator.mutate ~seed:42 program in
match Nala.Vm.run mutated with
| Ok result -> print_string result.output
| Error e -> fail eRead/write packages
let program =
match Nala.Package.read_file "program.nala" with
| Ok p -> p
| Error e -> fail e
let () =
match Nala.Package.write_file "copy.nala" program with
| Ok () -> ()
| Error e -> fail e#include "nala.h"Register a deterministic import
static nala_status_t doublefn(void *user, const int32_t *args, size_t argc,
int32_t *result, nala_error_t *error) {
(void)user;
(void)error;
if (argc != 1) return NALA_ERR_HOST;
*result = args[0] * 2;
return NALA_OK;
}Create a context, load a package, and run
nala_error_t error;
nala_context_t *ctx = nala_context_new(NULL);
nala_program_t *program = NULL;
nala_vm_t *vm = NULL;
nala_program_load(bytes, len, &program, &error);
nala_context_register_import(ctx, "double", 1, doublefn, NULL, &error);
nala_vm_new(ctx, program, &vm, &error);
nala_vm_run(vm, NULL, NULL, &error);
size_t outlen = 0;
const uint8_t *out = nala_vm_output(vm, &outlen);
fwrite(out, 1, outlen, stdout);
nala_vm_free(vm);
nala_program_free(program);
nala_context_free(ctx);