#include "runner.h" #include #include #include #include #include #include #include #include #define PUSHN(bits) \ pushToStack##bits##Bits(&stack, &stack_size, &stack_filled, \ getNext##bits##Bits(&ip)) #define LOADN(bits) \ pushToStack##bits##Bits(&stack, &stack_size, &stack_filled, \ *((uint##bits##_t *)popFromStack64Bits( \ &stack, &stack_size, &stack_filled))) #define POPN(bits) \ { \ uint##bits##_t *pointer = (uint##bits##_t *)popFromStack64Bits( \ &stack, &stack_size, &stack_filled); \ *pointer = popFromStack##bits##Bits(&stack, &stack_size, &stack_filled); \ } #define DUPN(bits) \ { \ const uint##bits##_t a = \ popFromStack##bits##Bits(&stack, &stack_size, &stack_filled); \ pushToStack##bits##Bits(&stack, &stack_size, &stack_filled, a); \ pushToStack##bits##Bits(&stack, &stack_size, &stack_filled, a); \ } #define SWAPN(bits) \ { \ const uint##bits##_t a = \ popFromStack##bits##Bits(&stack, &stack_size, &stack_filled); \ const uint##bits##_t b = \ popFromStack##bits##Bits(&stack, &stack_size, &stack_filled); \ pushToStack##bits##Bits(&stack, &stack_size, &stack_filled, a); \ pushToStack##bits##Bits(&stack, &stack_size, &stack_filled, b); \ } #define DROPN(bits) \ popFromStack##bits##Bits(&stack, &stack_size, &stack_filled); #define OPERATION(type, bits, op) \ { \ const uint##bits##_t a = \ popFromStack##bits##Bits(&stack, &stack_size, &stack_filled); \ const uint##bits##_t b = \ popFromStack##bits##Bits(&stack, &stack_size, &stack_filled); \ const type result = *((type *)&a)op * ((type *)&b); \ pushToStack##bits##Bits(&stack, &stack_size, &stack_filled, \ *(uint##bits##_t *)&result); \ } #define ADD(type, bits) OPERATION(type, bits, +) #define SUB(type, bits) OPERATION(type, bits, -) #define NEG(type, bits) \ { \ const type a = \ popFromStack##bits##Bits(&stack, &stack_size, &stack_filled); \ const type result = -a; \ pushToStack##bits##Bits(&stack, &stack_size, &stack_filled, \ *(uint##bits##_t *)&result); \ } #define MUL(type, bits) OPERATION(type, bits, *) #define DIV(type, bits) OPERATION(type, bits, /) #define REM(type, bits) OPERATION(type, bits, %) #define CAST(from, from_bits, to, to_bits) \ { \ const from a = \ popFromStack##from_bits##Bits(&stack, &stack_size, &stack_filled); \ const to result = a; \ pushToStack##to_bits##Bits(&stack, &stack_size, &stack_filled, \ *(uint##to_bits##_t *)&result); \ } #define COND_JUMP(type, bits, op) \ { \ const uint##bits##_t a = \ popFromStack##bits##Bits(&stack, &stack_size, &stack_filled); \ \ if (*((type *)&a)op 0) { \ ip = (uint8_t *)popFromStack64Bits(&stack, &stack_size, &stack_filled); \ } \ } int fasmRunner(ByteCode bytecode) { uint8_t *data = a404m_malloc(bytecode.data_size); size_t data_size = bytecode.data_size; memcpy(data, bytecode.data, data_size); uint8_t *code = bytecode.code; /*size_t code_size = bytecode.code_size;*/ size_t stack_size = 0; size_t stack_filled = 0; uint8_t *stack = a404m_malloc(stack_size); size_t functions_size = 0; size_t functions_index = -1; FasmFunction *functions = a404m_malloc(functions_size * sizeof(*functions)); uint8_t *ip = code; while (true) { const FasmToken instruction = *ip; ++ip; switch (instruction) { case FASM_TOKEN_NOOP: continue; case FASM_TOKEN_PUSH8: PUSHN(8); continue; case FASM_TOKEN_PUSH16: PUSHN(16); continue; case FASM_TOKEN_PUSH32: PUSHN(32); continue; case FASM_TOKEN_PUSH64: PUSHN(64); continue; case FASM_TOKEN_LOAD8: LOADN(8); continue; case FASM_TOKEN_LOAD16: LOADN(16); continue; case FASM_TOKEN_LOAD32: LOADN(32); continue; case FASM_TOKEN_LOAD64: LOADN(64); continue; case FASM_TOKEN_POP8: POPN(8); continue; case FASM_TOKEN_POP16: POPN(16); continue; case FASM_TOKEN_POP32: POPN(32); continue; case FASM_TOKEN_POP64: POPN(64); continue; case FASM_TOKEN_DUP8: DUPN(8); continue; case FASM_TOKEN_DUP16: DUPN(16); continue; case FASM_TOKEN_DUP32: DUPN(32); continue; case FASM_TOKEN_DUP64: DUPN(64); continue; case FASM_TOKEN_SWAP8: SWAPN(8); continue; case FASM_TOKEN_SWAP16: SWAPN(16); continue; case FASM_TOKEN_SWAP32: SWAPN(32); continue; case FASM_TOKEN_SWAP64: SWAPN(64); continue; case FASM_TOKEN_DROP8: DROPN(8); continue; case FASM_TOKEN_DROP16: DROPN(16); continue; case FASM_TOKEN_DROP32: DROPN(32); continue; case FASM_TOKEN_DROP64: DROPN(64); continue; case FASM_TOKEN_ADD_I8: ADD(uint8_t, 8); continue; case FASM_TOKEN_ADD_I16: ADD(uint16_t, 16); continue; case FASM_TOKEN_ADD_I32: ADD(uint32_t, 32); continue; case FASM_TOKEN_ADD_I64: ADD(uint64_t, 64); continue; case FASM_TOKEN_ADD_F32: ADD(float, 32); continue; case FASM_TOKEN_ADD_F64: ADD(double, 64); continue; case FASM_TOKEN_SUB_I8: SUB(uint8_t, 8); continue; case FASM_TOKEN_SUB_I16: SUB(uint16_t, 16); continue; case FASM_TOKEN_SUB_I32: SUB(uint32_t, 32); continue; case FASM_TOKEN_SUB_I64: SUB(uint64_t, 64); continue; case FASM_TOKEN_SUB_F32: SUB(float, 32); continue; case FASM_TOKEN_SUB_F64: SUB(double, 64); continue; case FASM_TOKEN_NEG_I8: NEG(int8_t, 8); continue; case FASM_TOKEN_NEG_I16: NEG(int16_t, 16); continue; case FASM_TOKEN_NEG_I32: NEG(int32_t, 32); continue; case FASM_TOKEN_NEG_I64: NEG(int64_t, 64); continue; case FASM_TOKEN_NEG_F32: NEG(float, 32); continue; case FASM_TOKEN_NEG_F64: NEG(double, 64); continue; case FASM_TOKEN_MUL_I8: MUL(int8_t, 8); continue; case FASM_TOKEN_MUL_I16: MUL(int16_t, 16); continue; case FASM_TOKEN_MUL_I32: MUL(int32_t, 32); continue; case FASM_TOKEN_MUL_I64: MUL(int64_t, 64); continue; case FASM_TOKEN_MUL_U8: MUL(uint8_t, 8); continue; case FASM_TOKEN_MUL_U16: MUL(uint16_t, 16); continue; case FASM_TOKEN_MUL_U32: MUL(uint32_t, 32); continue; case FASM_TOKEN_MUL_U64: MUL(uint64_t, 64); continue; case FASM_TOKEN_MUL_F32: MUL(float, 32); continue; case FASM_TOKEN_MUL_F64: MUL(double, 64); continue; case FASM_TOKEN_DIV_I8: DIV(int8_t, 8); continue; case FASM_TOKEN_DIV_I16: DIV(int16_t, 16); continue; case FASM_TOKEN_DIV_I32: DIV(int32_t, 32); continue; case FASM_TOKEN_DIV_I64: DIV(int64_t, 64); continue; case FASM_TOKEN_DIV_U8: DIV(uint8_t, 8); continue; case FASM_TOKEN_DIV_U16: DIV(uint16_t, 16); continue; case FASM_TOKEN_DIV_U32: DIV(uint32_t, 32); continue; case FASM_TOKEN_DIV_U64: DIV(uint64_t, 64); continue; case FASM_TOKEN_DIV_F32: DIV(float, 32); continue; case FASM_TOKEN_DIV_F64: DIV(double, 64); continue; case FASM_TOKEN_REM_I8: REM(int8_t, 8); continue; case FASM_TOKEN_REM_I16: REM(int16_t, 16); continue; case FASM_TOKEN_REM_I32: REM(int32_t, 32); continue; case FASM_TOKEN_REM_I64: REM(int64_t, 64); continue; case FASM_TOKEN_REM_U8: REM(uint8_t, 8); continue; case FASM_TOKEN_REM_U16: REM(uint16_t, 16); continue; case FASM_TOKEN_REM_U32: REM(uint32_t, 32); continue; case FASM_TOKEN_REM_U64: REM(uint64_t, 64); continue; case FASM_TOKEN_CAST_I8_I64: CAST(int8_t, 8, int64_t, 64); continue; case FASM_TOKEN_CAST_I16_I64: CAST(int16_t, 16, int64_t, 64); continue; case FASM_TOKEN_CAST_I32_I64: CAST(int32_t, 32, int64_t, 64); continue; case FASM_TOKEN_CAST_I64_I8: CAST(int64_t, 64, int8_t, 8); continue; case FASM_TOKEN_CAST_I64_I16: CAST(int64_t, 64, int16_t, 16); continue; case FASM_TOKEN_CAST_I64_I32: CAST(int64_t, 64, int32_t, 32); continue; case FASM_TOKEN_CAST_F64_I64: CAST(double, 64, int64_t, 64); continue; case FASM_TOKEN_CAST_I64_F64: CAST(int64_t, 64, double, 64); continue; case FASM_TOKEN_CAST_U8_U64: CAST(uint8_t, 8, uint64_t, 64); continue; case FASM_TOKEN_CAST_U16_U64: CAST(uint16_t, 16, uint64_t, 64); continue; case FASM_TOKEN_CAST_U32_U64: CAST(uint32_t, 32, uint64_t, 64); continue; case FASM_TOKEN_CAST_U64_U8: CAST(uint64_t, 64, uint8_t, 8); continue; case FASM_TOKEN_CAST_U64_U16: CAST(uint64_t, 64, uint16_t, 16); continue; case FASM_TOKEN_CAST_U64_U32: CAST(uint64_t, 64, uint32_t, 32); continue; case FASM_TOKEN_CAST_F64_U64: CAST(double, 64, uint64_t, 64); continue; case FASM_TOKEN_CAST_U64_F64: CAST(uint64_t, 64, double, 64); continue; case FASM_TOKEN_CAST_F32_F64: CAST(float, 32, double, 64); continue; case FASM_TOKEN_CAST_F64_F32: CAST(double, 64, float, 32); continue; case FASM_TOKEN_JUMP: ip = (uint8_t *)popFromStack64Bits(&stack, &stack_size, &stack_filled); continue; case FASM_TOKEN_JZ_I8: COND_JUMP(int8_t, 8, ==); continue; case FASM_TOKEN_JNZ_I8: COND_JUMP(int8_t, 8, !=); continue; case FASM_TOKEN_JN_I8: COND_JUMP(int8_t, 8, <); continue; case FASM_TOKEN_JNN_I8: COND_JUMP(int8_t, 8, >=); continue; case FASM_TOKEN_JP_I8: COND_JUMP(int8_t, 8, >); continue; case FASM_TOKEN_JNP_I8: COND_JUMP(int8_t, 8, <=); continue; case FASM_TOKEN_JZ_I16: COND_JUMP(int16_t, 16, ==); continue; case FASM_TOKEN_JNZ_I16: COND_JUMP(int16_t, 16, !=); continue; case FASM_TOKEN_JN_I16: COND_JUMP(int16_t, 16, <); continue; case FASM_TOKEN_JNN_I16: COND_JUMP(int16_t, 16, >=); continue; case FASM_TOKEN_JP_I16: COND_JUMP(int16_t, 16, >); continue; case FASM_TOKEN_JNP_I16: COND_JUMP(int16_t, 16, <=); continue; case FASM_TOKEN_JZ_I32: COND_JUMP(int32_t, 32, ==); continue; case FASM_TOKEN_JNZ_I32: COND_JUMP(int32_t, 32, !=); continue; case FASM_TOKEN_JN_I32: COND_JUMP(int32_t, 32, <); continue; case FASM_TOKEN_JNN_I32: COND_JUMP(int32_t, 32, >=); continue; case FASM_TOKEN_JP_I32: COND_JUMP(int32_t, 32, >); continue; case FASM_TOKEN_JNP_I32: COND_JUMP(int32_t, 32, <=); continue; case FASM_TOKEN_JZ_I64: COND_JUMP(int64_t, 64, ==); continue; case FASM_TOKEN_JNZ_I64: COND_JUMP(int64_t, 64, !=); continue; case FASM_TOKEN_JN_I64: COND_JUMP(int64_t, 64, <); continue; case FASM_TOKEN_JNN_I64: COND_JUMP(int64_t, 64, >=); continue; case FASM_TOKEN_JP_I64: COND_JUMP(int64_t, 64, >); continue; case FASM_TOKEN_JNP_I64: COND_JUMP(int64_t, 64, <=); continue; case FASM_TOKEN_JZ_F32: COND_JUMP(float, 32, ==); continue; case FASM_TOKEN_JNZ_F32: COND_JUMP(float, 32, !=); continue; case FASM_TOKEN_JN_F32: COND_JUMP(float, 32, <); continue; case FASM_TOKEN_JNN_F32: COND_JUMP(float, 32, >=); continue; case FASM_TOKEN_JP_F32: COND_JUMP(float, 32, >); continue; case FASM_TOKEN_JNP_F32: COND_JUMP(float, 32, <=); continue; case FASM_TOKEN_JZ_F64: COND_JUMP(double, 64, ==); continue; case FASM_TOKEN_JNZ_F64: COND_JUMP(double, 64, !=); continue; case FASM_TOKEN_JN_F64: COND_JUMP(double, 64, <); continue; case FASM_TOKEN_JNN_F64: COND_JUMP(double, 64, >=); continue; case FASM_TOKEN_JP_F64: COND_JUMP(double, 64, >); continue; case FASM_TOKEN_JNP_F64: COND_JUMP(double, 64, <=); continue; case FASM_TOKEN_ALLOC_HEAP: pushToStack64Bits(&stack, &stack_size, &stack_filled, (uint64_t)a404m_malloc(popFromStack64Bits( &stack, &stack_size, &stack_filled))); continue; case FASM_TOKEN_ALLOC_STACK: functions[functions_index].stack_size = popFromStack64Bits(&stack, &stack_size, &stack_filled); functions[functions_index].stack = a404m_malloc(functions[functions_index].stack_size); continue; case FASM_TOKEN_FREE_HEAP: free((void *)popFromStack64Bits(&stack, &stack_size, &stack_filled)); continue; case FASM_TOKEN_GET_STACK_ADDRESS: pushToStack64Bits(&stack, &stack_size, &stack_filled, (uint64_t)functions[functions_index].stack); continue; case FASM_TOKEN_GET_GLOBAL_ADDRESS: pushToStack64Bits(&stack, &stack_size, &stack_filled, (uint64_t)data); continue; case FASM_TOKEN_CALL: { uint8_t *const newIp = code + popFromStack64Bits(&stack, &stack_size, &stack_filled); ++functions_index; if (functions_index == functions_size) { functions_size += functions_size / 2 + 1; functions = a404m_realloc(functions, functions_size * sizeof(*functions)); } FasmFunction function = { .returnTo = ip, .stack = a404m_malloc(0), .stack_size = 0, }; functions[functions_index] = function; ip = newIp; } continue; case FASM_TOKEN_RET: { FasmFunction function = functions[functions_index]; free(function.stack); ip = function.returnTo; --functions_index; if (functions_index + sizeof(*functions) < functions_size / 2) { functions_size = functions_size / 2; functions = a404m_realloc(functions, functions_size * sizeof(*functions)); } } continue; case FASM_TOKEN_SYSCALL: { FasmSyscall syscallId = popFromStack8Bits(&stack, &stack_size, &stack_filled); switch (syscallId) { case FASM_SYSCALL_READ: { uint32_t fd = popFromStack32Bits(&stack, &stack_size, &stack_filled); int8_t *buf = (int8_t *)popFromStack64Bits(&stack, &stack_size, &stack_filled); uint64_t count = popFromStack64Bits(&stack, &stack_size, &stack_filled); syscall(SYS_read, fd, buf, count); } continue; case FASM_SYSCALL_WRITE: { uint32_t fd = popFromStack32Bits(&stack, &stack_size, &stack_filled); int8_t *buf = (int8_t *)popFromStack64Bits(&stack, &stack_size, &stack_filled); uint64_t count = popFromStack64Bits(&stack, &stack_size, &stack_filled); syscall(SYS_write, fd, buf, count); } continue; case FASM_SYSCALL_OPEN: { int8_t *filename = (int8_t *)popFromStack64Bits(&stack, &stack_size, &stack_filled); uint32_t flags = popFromStack32Bits(&stack, &stack_size, &stack_filled); uint32_t mode = popFromStack32Bits(&stack, &stack_size, &stack_filled); syscall(SYS_open, filename, flags, mode); } continue; case FASM_SYSCALL_CLOSE: { uint32_t fd = popFromStack32Bits(&stack, &stack_size, &stack_filled); syscall(SYS_close, fd); } continue; case FASM_SYSCALL_EXIT: for (size_t i = functions_index; i != (size_t)-1; --i) { free(functions[i].stack); } const uint32_t status = popFromStack32Bits(&stack, &stack_size, &stack_filled); free(functions); free(stack); free(data); return status; } fprintf(stderr, "Bad system call %d", syscallId); exit(1); } case FASM_TOKEN_DEFINE_BYTE: case FASM_TOKEN_DEFINE_WORD: case FASM_TOKEN_DEFINE_DWORD: case FASM_TOKEN_DEFINE_QWORD: case FASM_TOKEN_NONE: } fprintf(stderr, "Bad fasm instruction %d", instruction); exit(1); } } #define getNextNBits(bits) \ uint##bits##_t getNext##bits##Bits(uint8_t **pos) { \ uint##bits##_t value = *((uint##bits##_t *)(*pos)); \ *pos += sizeof(value); \ return value; \ } getNextNBits(8); getNextNBits(16); getNextNBits(32); getNextNBits(64); #define pushToStackNBits(bits) \ void pushToStack##bits##Bits(uint8_t **stack, size_t *stack_size, \ size_t *stack_filled, uint##bits##_t value) { \ const size_t new_stack_size = *stack_filled + sizeof(value); \ if (new_stack_size >= *stack_size) { \ *stack_size = new_stack_size + new_stack_size / 2 + 1; \ *stack = a404m_realloc(*stack, *stack_size); \ } \ *((uint##bits##_t *)(*stack + *stack_filled)) = value; \ *stack_filled = new_stack_size; \ } pushToStackNBits(8); pushToStackNBits(16); pushToStackNBits(32); pushToStackNBits(64); #define popFromStackNBit(bits) \ uint##bits##_t popFromStack##bits##Bits(uint8_t **stack, size_t *stack_size, \ size_t *stack_filled) { \ uint##bits##_t value; \ *stack_filled -= sizeof(value); \ value = *((uint##bits##_t *)(*stack + *stack_filled)); \ if (*stack_filled < *stack_size / 2) { \ *stack_size = *stack_filled; \ *stack = a404m_realloc(*stack, *stack_size); \ } \ return value; \ } popFromStackNBit(8); popFromStackNBit(16); popFromStackNBit(32); popFromStackNBit(64);