From 8840f68145c927463de4cd65c739da9977bedfda Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 16 Apr 2026 18:15:54 +0000 Subject: [PATCH 1/2] Add complex-app example with loops, pointers, structs, bit shifts and masks Agent-Logs-Url: https://github.com/corepunch/armvm/sessions/07d29fa2-b60c-433b-b1bc-cbbf5927fac1 Co-authored-by: corepunch <83646194+corepunch@users.noreply.github.com> --- examples/complex-app/Makefile | 63 ++++++++++ examples/complex-app/README.md | 97 ++++++++++++++++ examples/complex-app/complex-app | Bin 0 -> 57928 bytes examples/complex-app/complex.s | 194 +++++++++++++++++++++++++++++++ examples/complex-app/input.c | 87 ++++++++++++++ examples/complex-app/main.c | 136 ++++++++++++++++++++++ 6 files changed, 577 insertions(+) create mode 100644 examples/complex-app/Makefile create mode 100644 examples/complex-app/README.md create mode 100755 examples/complex-app/complex-app create mode 100644 examples/complex-app/complex.s create mode 100644 examples/complex-app/input.c create mode 100644 examples/complex-app/main.c diff --git a/examples/complex-app/Makefile b/examples/complex-app/Makefile new file mode 100644 index 0000000..a565064 --- /dev/null +++ b/examples/complex-app/Makefile @@ -0,0 +1,63 @@ +# Makefile for the complex-app example +# +# On macOS with Xcode command-line tools, 'make all' also regenerates +# complex.s from input.c using clang's ARMv7 cross-compiler. On Linux +# (or any host without clang -arch armv7), 'make app' builds and runs +# the pre-generated complex.s that is already checked into the repository. + +CC = gcc +CFLAGS = -Wall -Wextra -O2 +LDFLAGS = -lm + +ARMVM_DIR = ../../armvm +OBJDIR = build + +# armvm library sources (everything except compiler.c, which has its own main) +ARMVM_SRCS = \ + $(ARMVM_DIR)/armvm.c \ + $(ARMVM_DIR)/armcomp.c \ + $(ARMVM_DIR)/expr.c \ + $(ARMVM_DIR)/memory.c \ + $(ARMVM_DIR)/libpvm.c + +# compiler.c is compiled in isolation with -Dmain=_unused_main so that +# compile_buffer() and avm_loadbuffer() are available to link against +# without conflicting with our own main(). +COMPILER_SRC = $(ARMVM_DIR)/compiler.c +COMPILER_OBJ = $(OBJDIR)/compiler.o + +TARGET = complex-app +ASM_OUTPUT = complex.s + +.PHONY: all app run clean + +# 'all' attempts to regenerate the assembly from input.c (macOS only). +all: $(TARGET) $(ASM_OUTPUT) + +# 'app' builds the host runner against the pre-generated assembly. +app: $(TARGET) + +$(OBJDIR): + mkdir -p $(OBJDIR) + +# Regenerate ARM assembly from input.c using the Apple clang cross-compiler. +# This target only works on macOS with Xcode command-line tools installed. +$(ASM_OUTPUT): input.c + clang -S -arch armv7 -target armv7-apple-darwin -marm -O1 $< -o $@ + +# Compile compiler.c in isolation so its main() is renamed. +$(COMPILER_OBJ): $(COMPILER_SRC) | $(OBJDIR) + $(CC) $(CFLAGS) -I$(ARMVM_DIR) -Dmain=_unused_main -c $< -o $@ + +# Build the host runner. +$(TARGET): main.c $(COMPILER_OBJ) $(ARMVM_SRCS) + $(CC) $(CFLAGS) -I$(ARMVM_DIR) \ + main.c $(ARMVM_SRCS) $(COMPILER_OBJ) \ + $(LDFLAGS) -o $(TARGET) + +# Build and run using the pre-generated complex.s. +run: app + ./$(TARGET) $(ASM_OUTPUT) + +clean: + rm -rf $(OBJDIR) $(TARGET) diff --git a/examples/complex-app/README.md b/examples/complex-app/README.md new file mode 100644 index 0000000..62beff7 --- /dev/null +++ b/examples/complex-app/README.md @@ -0,0 +1,97 @@ +# complex-app example + +A more complex example showing how to embed **armvm** in a host application +with multiple exported functions, loops, pointer arithmetic, struct-like +field access, bit shifts, and bit masks. + +## What it demonstrates + +### `input.c` / `complex.s` + +Three internal ARM functions plus `main()`, all demonstrating different +language features: + +| Function | Features | +|---|---| +| `compute_flags(value, shift, mask)` | register-controlled bit shift (`lsl r1`), bit-AND mask | +| `sum_array(arr*, count)` | counted loop (`cmp`/`bge`/`b`), pointer walk via scaled register offset (`[r0, r4, lsl #2]`), callee-saved registers | +| `process_record(record*)` | struct-like field access via immediate offsets (`[r0, #4]`, `[r0, #8]`), immediate bit shift (`lsl #8`), bitwise OR | +| `main` | stack-allocated arrays, calling all helpers, PC-relative string addressing | + +### `main.c` + +The host application that: +1. Registers `print_int` and `print_string` as host functions accessible to ARM code +2. Loads and compiles `complex.s` via `avm_loadbuffer()` +3. Executes the program with `avm_call()` +4. Reads and prints the return value + +## Expected output + +``` +Running complex ARM32 program... +compute_flags result: 3840 +sum_array result: 150 +process_record result: 1834 +Program returned: 150 +``` + +### Result breakdown + +| Call | Computation | Result | +|---|---|---| +| `compute_flags(0xFF, 4, 0xF00)` | `(255 << 4) & 3840 = 4080 & 3840` | **3840** | +| `sum_array([10,20,30,40,50], 5)` | `10+20+30+40+50` | **150** | +| `process_record([1, 42, 7])` | `42 \| (7 << 8) = 42 \| 1792` | **1834** | + +## Build and run + +```bash +# from the repository root — build armvm first (if not already done) +make + +# build the host runner and run with the pre-generated assembly +make -C examples/complex-app run +``` + +On macOS with Xcode command-line tools you can also regenerate `complex.s` +from `input.c`: + +```bash +# regenerate assembly and run +make -C examples/complex-app all run +``` + +## Assembly highlights + +### Bit shift and mask (`_compute_flags`) + +```asm +_compute_flags: + mov r0, r0, lsl r1 @ r0 = value << shift (register-controlled) + and r0, r0, r2 @ r0 = (value << shift) & mask + bx lr +``` + +### Loop with pointer walk (`_sum_array`) + +```asm +_sum_loop: + cmp r4, r1 @ if i >= count, exit + bge _sum_done + ldr r2, [r0, r4, lsl #2] @ r2 = arr[i] (base + i*4) + add r5, r5, r2 + add r4, r4, #1 @ i++ + b _sum_loop +``` + +### Struct-like field access (`_process_record`) + +```asm +_process_record: + ldr r1, [r0, #4] @ value = record[1] + ldr r2, [r0, #8] @ flags = record[2] + mov r2, r2, lsl #8 @ flags << 8 + orr r0, r1, r2 @ value | (flags << 8) + bx lr +``` diff --git a/examples/complex-app/complex-app b/examples/complex-app/complex-app new file mode 100755 index 0000000000000000000000000000000000000000..d3dc2d1ff240dcdd02b424bff6e714c9a175e991 GIT binary patch literal 57928 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 literal 0 HcmV?d00001 diff --git a/examples/complex-app/complex.s b/examples/complex-app/complex.s new file mode 100644 index 0000000..5653531 --- /dev/null +++ b/examples/complex-app/complex.s @@ -0,0 +1,194 @@ +@ complex.s — Hand-written ARMv7 assembly for the complex-app example. +@ +@ Corresponds to input.c; generated manually because cross-compilation to +@ ARMv7 is only available on macOS. The syntax follows Apple/ARM UAL as +@ consumed by armvm's assembler (armcomp.c / compiler.c). +@ +@ Functions exported to the host via avm_register(): +@ print_int(int n) — prints an integer followed by a newline +@ print_string(const char*) — prints a NUL-terminated string +@ +@ Internal functions (resolved by the assembler's linker pass): +@ _compute_flags(value, shift, mask) -> (value << shift) & mask +@ _sum_array(arr*, count) -> sum of arr[0..count-1] +@ _process_record(record*) -> record[1] | (record[2] << 8) +@ +@ ARM calling convention (AAPCS): +@ Arguments : r0-r3 (first four integer args) +@ Return value: r0 +@ Callee-saved: r4-r11, sp, lr (push/pop in prologue/epilogue) +@ Caller-saved: r0-r3, r12 + + .section __TEXT,__text,regular,pure_instructions + .globl _main + .globl _compute_flags + .globl _sum_array + .globl _process_record + +@ ----------------------------------------------------------------------- +@ compute_flags(int value, int shift, int mask) -> int +@ +@ r0 = value, r1 = shift, r2 = mask +@ Returns (value << shift) & mask. +@ +@ Demonstrates: register-controlled bit shift (lsl r1), bit-AND mask. +@ ----------------------------------------------------------------------- +_compute_flags: + mov r0, r0, lsl r1 @ r0 = value << shift + and r0, r0, r2 @ r0 = (value << shift) & mask + bx lr + +@ ----------------------------------------------------------------------- +@ sum_array(int *arr, int count) -> int +@ +@ r0 = pointer to int array (in VM memory) +@ r1 = number of elements +@ Returns sum of arr[0] + arr[1] + ... + arr[count-1]. +@ +@ Demonstrates: loop (cmp/bge/b), pointer arithmetic via scaled register +@ offset ([r0, r4, lsl #2] = arr + i*4), callee-saved registers. +@ ----------------------------------------------------------------------- +_sum_array: + push { r4, r5, lr } + mov r4, #0 @ i = 0 + mov r5, #0 @ total = 0 +_sum_loop: + cmp r4, r1 @ if i >= count, exit + bge _sum_done + ldr r2, [r0, r4, lsl #2] @ r2 = arr[i] (arr + i*4) + add r5, r5, r2 @ total += arr[i] + add r4, r4, #1 @ i++ + b _sum_loop +_sum_done: + mov r0, r5 @ return total + pop { r4, r5, pc } + +@ ----------------------------------------------------------------------- +@ process_record(int *record) -> int +@ +@ r0 = pointer to int[3]: { id, value, flags } +@ Returns record[1] | (record[2] << 8). +@ +@ Demonstrates: struct-like field access via immediate offsets, +@ immediate bit shift (lsl #8), bitwise OR. +@ ----------------------------------------------------------------------- +_process_record: + ldr r1, [r0, #4] @ r1 = record[1] (value) + ldr r2, [r0, #8] @ r2 = record[2] (flags) + mov r2, r2, lsl #8 @ r2 = flags << 8 + orr r0, r1, r2 @ r0 = value | (flags << 8) + bx lr + +@ ----------------------------------------------------------------------- +@ main() — entry point +@ +@ Stack frame layout (after push + sub): +@ [sp + 0 .. +16] arr[5] (5 × int = 20 bytes) +@ [sp + 20 .. +28] record[3] (3 × int = 12 bytes) +@ — 32 bytes total — +@ +@ Registers used: +@ r4 = compute_flags result +@ r5 = sum_array result (also the return value) +@ r6 = process_record result +@ +@ Returns: sum_array result (150). +@ ----------------------------------------------------------------------- +_main: + push { r4, r5, r6, lr } + sub sp, sp, #32 @ allocate 32 bytes for locals + + @ ---- 1. compute_flags(0xFF, 4, 0xF00) ---- + @ (0xFF << 4) & 0xF00 = 0xFF0 & 0xF00 = 0xF00 = 3840 + mov r0, #255 @ value = 0xFF + mov r1, #4 @ shift = 4 + mov r2, #3840 @ mask = 0xF00 + bl _compute_flags + mov r4, r0 @ save flags result (3840) + + ldr r0, LCPI0_0 +LPC0_0: + add r0, pc, r0 @ r0 = address of string "compute_flags result: " + bl _print_string + + mov r0, r4 + bl _print_int + + @ ---- 2. sum_array({10,20,30,40,50}, 5) ---- + @ Build arr[5] on the stack at [sp, #0..#16] + mov r0, #10 + str r0, [sp, #0] + mov r0, #20 + str r0, [sp, #4] + mov r0, #30 + str r0, [sp, #8] + mov r0, #40 + str r0, [sp, #12] + mov r0, #50 + str r0, [sp, #16] + + mov r0, sp @ r0 = &arr[0] + mov r1, #5 @ count = 5 + bl _sum_array + mov r5, r0 @ save total (150) + + ldr r0, LCPI0_1 +LPC0_1: + add r0, pc, r0 @ r0 = address of string "sum_array result: " + bl _print_string + + mov r0, r5 + bl _print_int + + @ ---- 3. process_record({1, 42, 7}) ---- + @ Build record[3] on the stack at [sp, #20..#28] + @ record = { id=1, value=42, flags=7 } + @ result = 42 | (7 << 8) = 42 | 1792 = 1834 + mov r0, #1 + str r0, [sp, #20] + mov r0, #42 + str r0, [sp, #24] + mov r0, #7 + str r0, [sp, #28] + + add r0, sp, #20 @ r0 = &record[0] + bl _process_record + mov r6, r0 @ save processed (1834) + + ldr r0, LCPI0_2 +LPC0_2: + add r0, pc, r0 @ r0 = address of string "process_record result: " + bl _print_string + + mov r0, r6 + bl _print_int + + @ ---- return total (150) ---- + mov r0, r5 + add sp, sp, #32 + pop { r4, r5, r6, pc } + +@ ----------------------------------------------------------------------- +@ PC-relative string address constants +@ +@ Each LCPI0_x holds (label_address - (LPC0_x + 8)), so that at runtime: +@ ldr r0, LCPI0_x -> r0 = offset +@ add r0, pc, r0 -> r0 = absolute address in VM memory +@ +@ The PC value used in the add is the address of LPC0_x + 8 because the +@ ARM PC is always 2 instructions (8 bytes) ahead. +@ ----------------------------------------------------------------------- + .p2align 2 +LCPI0_0: + .long L_str0-(LPC0_0+8) +LCPI0_1: + .long L_str1-(LPC0_1+8) +LCPI0_2: + .long L_str2-(LPC0_2+8) + +L_str0: + .asciz "compute_flags result: " +L_str1: + .asciz "sum_array result: " +L_str2: + .asciz "process_record result: " diff --git a/examples/complex-app/input.c b/examples/complex-app/input.c new file mode 100644 index 0000000..54d0dc6 --- /dev/null +++ b/examples/complex-app/input.c @@ -0,0 +1,87 @@ +/* + * input.c - Complex example C program compiled to ARMv7 assembly for use + * with armvm. + * + * This file demonstrates several language features: + * - Multiple exported functions + * - Loops + * - Function calls + * - Pointer operations + * - Struct-like field access (int array acting as a struct) + * - Bit shifts + * - Bit masks + * + * To regenerate the assembly on macOS: + * clang -S -arch armv7 -target armv7-apple-darwin -O1 input.c -o complex.s + * + * Expected output when run via complex-app: + * compute_flags result: 3840 + * sum_array result: 150 + * process_record result: 1834 + * Program returned: 150 + */ + +/* Host functions provided by the host application via the syscall interface */ +extern int print_int(int n); +extern int print_string(const char *s); + +/* + * compute_flags — bit-shift and bit-mask demonstration. + * + * Shifts 'value' left by 'shift' bits, then masks with 'mask'. + * Example: compute_flags(0xFF, 4, 0xF00) = (0xFF << 4) & 0xF00 = 0xF00 = 3840 + */ +static int compute_flags(int value, int shift, int mask) { + return (value << shift) & mask; +} + +/* + * sum_array — loop and pointer demonstration. + * + * Iterates over an integer array and returns the sum of all elements. + */ +static int sum_array(int *arr, int count) { + int total = 0; + for (int i = 0; i < count; i++) { + total += arr[i]; + } + return total; +} + +/* + * process_record — struct-like pointer access demonstration. + * + * Treats a three-element int array as a record: + * record[0] = id (not used in result) + * record[1] = value + * record[2] = flags + * + * Returns value | (flags << 8), combining value and flags via bit ops. + * Example: process_record({1, 42, 7}) = 42 | (7 << 8) = 42 | 1792 = 1834 + */ +static int process_record(int *record) { + int value = record[1]; /* +4 bytes from base */ + int flags = record[2]; /* +8 bytes from base */ + return value | (flags << 8); +} + +int main(void) { + /* 1. Bit shifts and masks */ + int flags = compute_flags(0xFF, 4, 0xF00); /* = 3840 */ + print_string("compute_flags result: "); + print_int(flags); + + /* 2. Loop over a pointer/array */ + int arr[5] = {10, 20, 30, 40, 50}; + int total = sum_array(arr, 5); /* = 150 */ + print_string("sum_array result: "); + print_int(total); + + /* 3. Struct-like pointer access + bit ops */ + int record[3] = {1, 42, 7}; + int processed = process_record(record); /* = 1834 */ + print_string("process_record result: "); + print_int(processed); + + return total; /* 150 */ +} diff --git a/examples/complex-app/main.c b/examples/complex-app/main.c new file mode 100644 index 0000000..6c19b56 --- /dev/null +++ b/examples/complex-app/main.c @@ -0,0 +1,136 @@ +/* + * main.c - Host application for the complex-app example. + * + * Demonstrates embedding the ARM VM in a host application with multiple + * host functions exposed to the ARM guest code. + * + * Host functions registered: + * print_int(int n) — prints an integer followed by a newline + * print_string(const char*) — prints a NUL-terminated string + * + * Expected output: + * Running complex ARM32 program... + * compute_flags result: 3840 + * sum_array result: 150 + * process_record result: 1834 + * Program returned: 150 + * + * Usage: + * ./complex-app complex.s + */ + +#include +#include +#include + +#include "avm.h" + +/* ---------------------------------------------------------------------- */ +/* Host functions exposed to the ARM VM via avm_register() */ +/* ---------------------------------------------------------------------- */ + +/* + * print_int(int n) + * + * Reads the integer from r0 (register index 1) and prints it with a + * trailing newline. + */ +static int host_print_int(avm_State *S) { + int n = avm_tointeger(S, 1); + printf("%d\n", n); + return 0; /* void — no return value */ +} + +/* + * print_string(const char *s) + * + * ARM calling convention: s is passed as a VM-memory offset in r0. + * We validate the offset and verify NUL-termination before printing. + */ +static int host_print_string(avm_State *S) { + DWORD offset = avm_touinteger(S, 1); + DWORD mem_size = S->progsize + S->stacksize + S->heapsize; + if (offset >= mem_size) return 0; /* offset out of range */ + const char *base = (const char *)S->memory + offset; + DWORD max_len = mem_size - offset; + /* Verify the string is NUL-terminated within the addressable range */ + DWORD len = 0; + while (len < max_len && base[len] != '\0') len++; + if (len == max_len) return 0; /* not NUL-terminated */ + if (fwrite(base, 1, len, stdout) != len) return 0; + return 0; /* void — no return value */ +} + +/* ---------------------------------------------------------------------- */ +/* Utility */ +/* ---------------------------------------------------------------------- */ + +static char *read_file(const char *path) { + FILE *f = fopen(path, "r"); + if (!f) { + fprintf(stderr, "Cannot open '%s'\n", path); + return NULL; + } + fseek(f, 0, SEEK_END); + long size = ftell(f); + fseek(f, 0, SEEK_SET); + char *buf = malloc((size_t)size + 1); + if (!buf) { fclose(f); return NULL; } + fread(buf, (size_t)size, 1, f); + buf[size] = '\0'; + fclose(f); + return buf; +} + +/* ---------------------------------------------------------------------- */ +/* Main */ +/* ---------------------------------------------------------------------- */ + +int main(int argc, char *argv[]) { + if (argc < 2) { + fprintf(stderr, "Usage: %s \n", argv[0]); + return 1; + } + + char *src = read_file(argv[1]); + if (!src) + return 1; + + if (!strstr(src, "_main:")) { + fprintf(stderr, "error: assembly source does not define a '_main:' label\n"); + free(src); + return 1; + } + + /* 1. Create the VM state (64 KB stack, 64 KB heap). */ + avm_State *S = avm_newstate(VM_STACK_SIZE, VM_HEAP_SIZE); + + /* 2. Register host functions before loading code. + * + * ARM assembly calls these with "bl _print_int" / "bl _print_string". + * The leading underscore is stripped; we register the bare name here. + */ + avm_register(S, "print_int", host_print_int); + avm_register(S, "print_string", host_print_string); + + /* 3. Compile and load the assembly source. */ + if (avm_loadbuffer(S, src, strlen(src)) != 0) { + fprintf(stderr, "Compilation failed\n"); + free(src); + avm_close(S); + return 1; + } + free(src); + + /* 4. Execute from the _main entry point. */ + printf("Running complex ARM32 program...\n"); + avm_call(S, S->entry_point); + + /* 5. Read the integer return value from r0 (register index 1). */ + int result = avm_tointeger(S, 1); + printf("Program returned: %d\n", result); + + /* 6. Clean up. */ + avm_close(S); + return 0; +} From d02c95af9a1a8e433febe7d7c8fc16644f636a48 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 16 Apr 2026 18:16:17 +0000 Subject: [PATCH 2/2] Remove compiled binary; add .gitignore for complex-app build artifacts Agent-Logs-Url: https://github.com/corepunch/armvm/sessions/07d29fa2-b60c-433b-b1bc-cbbf5927fac1 Co-authored-by: corepunch <83646194+corepunch@users.noreply.github.com> --- examples/complex-app/.gitignore | 2 ++ examples/complex-app/complex-app | Bin 57928 -> 0 bytes 2 files changed, 2 insertions(+) create mode 100644 examples/complex-app/.gitignore delete mode 100755 examples/complex-app/complex-app diff --git a/examples/complex-app/.gitignore b/examples/complex-app/.gitignore new file mode 100644 index 0000000..abcfcd9 --- /dev/null +++ b/examples/complex-app/.gitignore @@ -0,0 +1,2 @@ +complex-app +build/ diff --git a/examples/complex-app/complex-app b/examples/complex-app/complex-app deleted file mode 100755 index d3dc2d1ff240dcdd02b424bff6e714c9a175e991..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 57928 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