Created
June 10, 2025 00:38
-
-
Save thaolt/a71cf5e133bb55c22f6f5a83abcfca97 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <stdint.h> | |
#include <stdbool.h> | |
// VM Configuration | |
#define STACK_SIZE 1024 | |
#define MAX_STRING_LENGTH 256 | |
#define ENCRYPTION_KEY 0xAB | |
// Opcodes for the VM | |
typedef enum { | |
OP_NOP = 0x00, // No operation | |
OP_PUSH = 0x01, // Push value onto stack | |
OP_POP = 0x02, // Pop value from stack | |
OP_ADD = 0x03, // Add two values | |
OP_SUB = 0x04, // Subtract two values | |
OP_MUL = 0x05, // Multiply two values | |
OP_DIV = 0x06, // Divide two values | |
OP_MOD = 0x07, // Modulo operation | |
OP_PRINT_INT = 0x08, // Print integer from stack | |
OP_PRINT_STR = 0x09, // Print decrypted string | |
OP_HALT = 0xFF // Halt execution | |
} Opcode; | |
// VM State Structure | |
typedef struct { | |
int32_t stack[STACK_SIZE]; | |
int32_t sp; // Stack pointer | |
uint8_t *bytecode; // Bytecode instructions | |
size_t pc; // Program counter | |
size_t bytecode_size; // Size of bytecode | |
bool running; // VM running state | |
} VM; | |
// Encrypted string structure | |
typedef struct { | |
uint8_t *data; | |
size_t length; | |
} EncryptedString; | |
// Function prototypes | |
VM* vm_create(void); | |
void vm_destroy(VM *vm); | |
bool vm_load_bytecode(VM *vm, uint8_t *bytecode, size_t size); | |
void vm_execute(VM *vm); | |
bool vm_push(VM *vm, int32_t value); | |
bool vm_pop(VM *vm, int32_t *value); | |
void vm_print_stack(VM *vm); | |
// String encryption/decryption functions | |
EncryptedString* encrypt_string(const char *plaintext); | |
char* decrypt_string(EncryptedString *encrypted); | |
void free_encrypted_string(EncryptedString *encrypted); | |
// Utility functions | |
uint32_t read_uint32(uint8_t *data, size_t offset); | |
void vm_error(const char *message); | |
// VM Creation and Destruction | |
VM* vm_create(void) { | |
VM *vm = malloc(sizeof(VM)); | |
if (!vm) { | |
vm_error("Failed to allocate memory for VM"); | |
return NULL; | |
} | |
memset(vm->stack, 0, sizeof(vm->stack)); | |
vm->sp = -1; | |
vm->bytecode = NULL; | |
vm->pc = 0; | |
vm->bytecode_size = 0; | |
vm->running = false; | |
printf("VM created successfully\n"); | |
return vm; | |
} | |
void vm_destroy(VM *vm) { | |
if (vm) { | |
if (vm->bytecode) { | |
free(vm->bytecode); | |
} | |
free(vm); | |
printf("VM destroyed\n"); | |
} | |
} | |
// Bytecode loading | |
bool vm_load_bytecode(VM *vm, uint8_t *bytecode, size_t size) { | |
if (!vm || !bytecode || size == 0) { | |
return false; | |
} | |
vm->bytecode = malloc(size); | |
if (!vm->bytecode) { | |
vm_error("Failed to allocate memory for bytecode"); | |
return false; | |
} | |
memcpy(vm->bytecode, bytecode, size); | |
vm->bytecode_size = size; | |
vm->pc = 0; | |
vm->running = false; | |
printf("Bytecode loaded: %zu bytes\n", size); | |
return true; | |
} | |
// Stack operations | |
bool vm_push(VM *vm, int32_t value) { | |
if (vm->sp >= STACK_SIZE - 1) { | |
vm_error("Stack overflow"); | |
return false; | |
} | |
vm->stack[++vm->sp] = value; | |
return true; | |
} | |
bool vm_pop(VM *vm, int32_t *value) { | |
if (vm->sp < 0) { | |
vm_error("Stack underflow"); | |
return false; | |
} | |
*value = vm->stack[vm->sp--]; | |
return true; | |
} | |
// Main execution engine | |
void vm_execute(VM *vm) { | |
if (!vm || !vm->bytecode) { | |
vm_error("Invalid VM state for execution"); | |
return; | |
} | |
vm->running = true; | |
vm->pc = 0; | |
printf("Starting VM execution...\n"); | |
while (vm->running && vm->pc < vm->bytecode_size) { | |
uint8_t opcode = vm->bytecode[vm->pc++]; | |
switch (opcode) { | |
case OP_NOP: | |
// No operation | |
break; | |
case OP_PUSH: { | |
if (vm->pc + 4 > vm->bytecode_size) { | |
vm_error("Incomplete PUSH instruction"); | |
vm->running = false; | |
break; | |
} | |
uint32_t value = read_uint32(vm->bytecode, vm->pc); | |
vm->pc += 4; | |
if (!vm_push(vm, (int32_t)value)) { | |
vm->running = false; | |
} | |
break; | |
} | |
case OP_POP: { | |
int32_t value; | |
if (!vm_pop(vm, &value)) { | |
vm->running = false; | |
} | |
break; | |
} | |
case OP_ADD: { | |
int32_t b, a; | |
if (!vm_pop(vm, &b) || !vm_pop(vm, &a)) { | |
vm->running = false; | |
break; | |
} | |
if (!vm_push(vm, a + b)) { | |
vm->running = false; | |
} | |
break; | |
} | |
case OP_SUB: { | |
int32_t b, a; | |
if (!vm_pop(vm, &b) || !vm_pop(vm, &a)) { | |
vm->running = false; | |
break; | |
} | |
if (!vm_push(vm, a - b)) { | |
vm->running = false; | |
} | |
break; | |
} | |
case OP_MUL: { | |
int32_t b, a; | |
if (!vm_pop(vm, &b) || !vm_pop(vm, &a)) { | |
vm->running = false; | |
break; | |
} | |
if (!vm_push(vm, a * b)) { | |
vm->running = false; | |
} | |
break; | |
} | |
case OP_DIV: { | |
int32_t b, a; | |
if (!vm_pop(vm, &b) || !vm_pop(vm, &a)) { | |
vm->running = false; | |
break; | |
} | |
if (b == 0) { | |
vm_error("Division by zero"); | |
vm->running = false; | |
break; | |
} | |
if (!vm_push(vm, a / b)) { | |
vm->running = false; | |
} | |
break; | |
} | |
case OP_MOD: { | |
int32_t b, a; | |
if (!vm_pop(vm, &b) || !vm_pop(vm, &a)) { | |
vm->running = false; | |
break; | |
} | |
if (b == 0) { | |
vm_error("Modulo by zero"); | |
vm->running = false; | |
break; | |
} | |
if (!vm_push(vm, a % b)) { | |
vm->running = false; | |
} | |
break; | |
} | |
case OP_PRINT_INT: { | |
int32_t value; | |
if (!vm_pop(vm, &value)) { | |
vm->running = false; | |
break; | |
} | |
printf("Output: %d\n", value); | |
break; | |
} | |
case OP_PRINT_STR: { | |
// Read string length | |
if (vm->pc + 4 > vm->bytecode_size) { | |
vm_error("Incomplete PRINT_STR instruction"); | |
vm->running = false; | |
break; | |
} | |
uint32_t str_length = read_uint32(vm->bytecode, vm->pc); | |
vm->pc += 4; | |
if (vm->pc + str_length > vm->bytecode_size) { | |
vm_error("String data exceeds bytecode bounds"); | |
vm->running = false; | |
break; | |
} | |
// Create encrypted string structure | |
EncryptedString encrypted; | |
encrypted.data = &vm->bytecode[vm->pc]; | |
encrypted.length = str_length; | |
// Decrypt and print | |
char *decrypted = decrypt_string(&encrypted); | |
if (decrypted) { | |
printf("Output: %s\n", decrypted); | |
free(decrypted); | |
} | |
vm->pc += str_length; | |
break; | |
} | |
case OP_HALT: | |
printf("VM halted normally\n"); | |
vm->running = false; | |
break; | |
default: | |
printf("Unknown opcode: 0x%02X at PC: %zu\n", opcode, vm->pc - 1); | |
vm->running = false; | |
break; | |
} | |
} | |
if (vm->running) { | |
printf("VM reached end of bytecode\n"); | |
} | |
} | |
// String encryption/decryption | |
EncryptedString* encrypt_string(const char *plaintext) { | |
if (!plaintext) return NULL; | |
size_t len = strlen(plaintext); | |
EncryptedString *encrypted = malloc(sizeof(EncryptedString)); | |
if (!encrypted) return NULL; | |
encrypted->data = malloc(len); | |
if (!encrypted->data) { | |
free(encrypted); | |
return NULL; | |
} | |
encrypted->length = len; | |
// Simple XOR encryption | |
for (size_t i = 0; i < len; i++) { | |
encrypted->data[i] = plaintext[i] ^ ENCRYPTION_KEY; | |
} | |
return encrypted; | |
} | |
char* decrypt_string(EncryptedString *encrypted) { | |
if (!encrypted || !encrypted->data) return NULL; | |
char *plaintext = malloc(encrypted->length + 1); | |
if (!plaintext) return NULL; | |
// Simple XOR decryption | |
for (size_t i = 0; i < encrypted->length; i++) { | |
plaintext[i] = encrypted->data[i] ^ ENCRYPTION_KEY; | |
} | |
plaintext[encrypted->length] = '\0'; | |
return plaintext; | |
} | |
void free_encrypted_string(EncryptedString *encrypted) { | |
if (encrypted) { | |
if (encrypted->data) { | |
free(encrypted->data); | |
} | |
free(encrypted); | |
} | |
} | |
// Utility functions | |
uint32_t read_uint32(uint8_t *data, size_t offset) { | |
return (uint32_t)data[offset] | | |
((uint32_t)data[offset + 1] << 8) | | |
((uint32_t)data[offset + 2] << 16) | | |
((uint32_t)data[offset + 3] << 24); | |
} | |
void vm_error(const char *message) { | |
fprintf(stderr, "VM Error: %s\n", message); | |
} | |
void vm_print_stack(VM *vm) { | |
printf("Stack state (SP=%d):\n", vm->sp); | |
for (int i = vm->sp; i >= 0; i--) { | |
printf(" [%d]: %d\n", i, vm->stack[i]); | |
} | |
} | |
// Helper function to create bytecode with embedded encrypted strings | |
size_t create_sample_bytecode(uint8_t **bytecode_out) { | |
// Sample program: Calculate (10 + 5) * 3 and print result, then print string | |
// Encrypt sample string | |
EncryptedString *encrypted = encrypt_string("Hello, VM World!"); | |
if (!encrypted) { | |
*bytecode_out = NULL; | |
return 0; | |
} | |
// Calculate bytecode size | |
size_t base_size = 1 + 5 + 1 + 5 + 1 + 1 + 5 + 1 + 1 + 1; // Basic arithmetic operations | |
size_t string_size = 1 + 4 + encrypted->length + 1; // PRINT_STR + length + data + HALT | |
size_t total_size = base_size + string_size; | |
uint8_t *bytecode = malloc(total_size); | |
if (!bytecode) { | |
free_encrypted_string(encrypted); | |
*bytecode_out = NULL; | |
return 0; | |
} | |
size_t offset = 0; | |
// PUSH 10 | |
bytecode[offset++] = OP_PUSH; | |
bytecode[offset++] = 10; | |
bytecode[offset++] = 0; | |
bytecode[offset++] = 0; | |
bytecode[offset++] = 0; | |
// PUSH 5 | |
bytecode[offset++] = OP_PUSH; | |
bytecode[offset++] = 5; | |
bytecode[offset++] = 0; | |
bytecode[offset++] = 0; | |
bytecode[offset++] = 0; | |
// ADD | |
bytecode[offset++] = OP_ADD; | |
// PUSH 3 | |
bytecode[offset++] = OP_PUSH; | |
bytecode[offset++] = 3; | |
bytecode[offset++] = 0; | |
bytecode[offset++] = 0; | |
bytecode[offset++] = 0; | |
// MUL | |
bytecode[offset++] = OP_MUL; | |
// PRINT_INT | |
bytecode[offset++] = OP_PRINT_INT; | |
// PRINT_STR with encrypted string | |
bytecode[offset++] = OP_PRINT_STR; | |
// String length (little endian) | |
uint32_t str_len = encrypted->length; | |
bytecode[offset++] = str_len & 0xFF; | |
bytecode[offset++] = (str_len >> 8) & 0xFF; | |
bytecode[offset++] = (str_len >> 16) & 0xFF; | |
bytecode[offset++] = (str_len >> 24) & 0xFF; | |
// Encrypted string data | |
memcpy(&bytecode[offset], encrypted->data, encrypted->length); | |
offset += encrypted->length; | |
// HALT | |
bytecode[offset++] = OP_HALT; | |
free_encrypted_string(encrypted); | |
*bytecode_out = bytecode; | |
return offset; | |
} | |
// Main function with example usage | |
int main(void) { | |
printf("Stack-Based Bytecode VM Engine\n"); | |
printf("==============================\n\n"); | |
// Create VM instance | |
VM *vm = vm_create(); | |
if (!vm) { | |
return 1; | |
} | |
// Create sample bytecode | |
uint8_t *bytecode; | |
size_t bytecode_size = create_sample_bytecode(&bytecode); | |
if (!bytecode) { | |
printf("Failed to create sample bytecode\n"); | |
vm_destroy(vm); | |
return 1; | |
} | |
// Load and execute bytecode | |
if (vm_load_bytecode(vm, bytecode, bytecode_size)) { | |
printf("\nExecuting sample program...\n"); | |
printf("Program: (10 + 5) * 3, then print string\n\n"); | |
vm_execute(vm); | |
printf("\nFinal stack state:\n"); | |
vm_print_stack(vm); | |
} | |
// Cleanup | |
free(bytecode); | |
vm_destroy(vm); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment