-
-
Save Killaship/927951649bbf2f2399565c5f4b47c621 to your computer and use it in GitHub Desktop.
/* | |
Killaship | |
2022 | |
November 13th, ~10:30 PM EST | |
This took like an hour or two to make, WITH a tutorial and previous experience! | |
A VM following the specifications of the 'mac' architecture, as outlined in this blog: | |
https://felix.engineer/blogs/virtual-machine-in-c/ | |
I was pretty tired while writing this, so the code might suck. | |
Hell, I typed & instead of % twice and was wondering for minutes about it! | |
I started work on this at ~ 9:15, I recorded the progress. | |
Notes: | |
- In loops, stack overflows only happen if your program is "unbalanced," | |
i.e., end up pushing more than there's space for. If a program is balanced, it'll run forever. | |
It might be hard to get a ^C in, so beware. | |
- There's a very limited instruction set, either add to it on your own, | |
or wait for me to, if I ever do. You'd be better off following the original creator of mac, | |
found at this Github link: https://github.com/felixangell/mac | |
I only did the bare minimum to make what's outlined in the blog work. | |
*/ | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <stdbool.h> | |
#include <string.h> | |
int ip = 0; | |
int sp = -1; | |
bool run = true; | |
typedef enum { // this gives us reference names for the opcodes. | |
PSH, | |
ADD, | |
POP, | |
SET, | |
STKRESET, | |
JMP, | |
HLT | |
} ISA; | |
typedef enum { | |
A, B, C, D, E, F, SP, IP, // I spent longer trying to copy paste this than to actually type it :/ | |
NUM_OF_REGISTERS | |
} REG; | |
int registers[NUM_OF_REGISTERS]; // what's funny is that you can use the NUM_OF_REGISTERS register as a register if you tried to in code | |
#define sp (registers[SP]) | |
#define ip (registers[IP]) | |
// ^^ quick lil' hack | |
int program[] = { // unsigned char instead of int since we don't need billions of opcodes | |
STKRESET, // wow, looks like we do need this. | |
PSH, 5, // well, fuck it, I just realized we need to add or subtract large numbers | |
PSH, 6, // I mean, we could go all harvard arch, but that would kinda suck ass | |
ADD, | |
POP, | |
JMP, 0, | |
HLT | |
}; | |
int stack[256]; // stack array | |
int fetch() { | |
return program[ip]; // FFS, this doesn't need a function | |
} | |
void eval(int instr) { | |
// what kind of crack was that guy's compiler smoking? | |
// maybe it was llvm | |
int a = 69; // debug values | |
int b = 69; | |
int result = 69; | |
int val_popped = 69; | |
int pushval = 69; | |
switch(instr) { | |
case POP: | |
val_popped = stack[sp--]; // MAKE SURE THE INC/DEC IS ON THE RIGHT GODDAMN SIDE | |
printf("popped %d!\n", val_popped); | |
break; | |
case ADD: | |
a = stack[sp--]; | |
printf("a is %d!\n", a); // I really would be better off using GDB but who cares | |
b = stack[sp--]; | |
printf("b is %d!\n", b); // I really would be better off using GDB but who cares | |
result = b + a; | |
printf("a plus b is %d!\n", result); // I really would be better off using GDB but who cares | |
sp++; // increment stack pointer **before** | |
stack[sp] = result; // set the value to the top of the stack | |
printf("I just pushed %d!\n", stack[sp]); | |
break; | |
case PSH: | |
sp++; | |
stack[sp] = program[++ip]; | |
pushval = stack[sp]; | |
printf("pushed %d!\n", pushval); // grammar laws request that the comma is included inside the quotation mark | |
stack[sp] = pushval; // this uses something I didn't know about before I first read the blog | |
break; // it uses the ++ lvalue to increment the ip at the same time as reading it | |
case SET: // nevermind | |
registers[program[ip++]] = registers[program[ip++]]; // zoo wee mama this is weird | |
// it increments the IP and then in the same line increments it again | |
break; | |
case STKRESET: // stack reset | |
memset(&stack, 0, 256); // should really unhardcode this later | |
sp = -1; | |
break; | |
case JMP: | |
printf("before: %d. ", ip); // I should get sleep, I mistyped something really obvious | |
ip = program[++ip]; // brain farted here | |
printf("after %d.\n", ip); | |
break; | |
case HLT: | |
run = false; | |
break; | |
} | |
} | |
int main() { | |
int instr = program[ip]; | |
while(run == true) { | |
instr = fetch(); | |
eval(instr); | |
ip++; | |
} | |
printf("done!\n"); | |
return 0; | |
} |
src/main.c 2008 gcc src/main.c
2009 ./a.out
2010 gcc src/main.c
2011 ./a.out
2012 gcc src/main.c
2013 ./a.out
2014 # jesus fucking christ what am I missing
2015 # does 5 + 6 really equal 0
2016 # is my whole life a lie
2017 gcc src/main.c
2018 ./a.out
2019 gcc src/main.c
2020 # no, my life isn't a lie
2021 # -- was on the wrong side
2022 ./a.out
2023 gcc src/main.c
2024 ./a.out
2025 # whoops, didn't need it at all
2026 # I was probably reading from un alloc'd memory
2027 gcc src/main.c
2028 ./a.out
2029 gcc src/main.c
2030 ./a.out
2031 gcc src/main.c
2032 ./a.out
2033 gcc src/main.c
2034 ./a.out
2035 gcc src/main.c
2036 ./a.out
2037 gcc src/main.c
2038 ./a.out
2039 gcc src/main.c
2040 ./a.out
2041 gcc src/main.c
2042 ./a.out
2043 # dafuq
2044 ./a.out
2045 gcc src/main.c
2046 ./a.out
2047 # there we go
2048 gcc src/main.c
2049 ./a.out
2050 gcc src/main.c
2051 ./a.out
2052 gcc src/main.c
2053 ./a.out
2054 # BWAHAHAHA
2055 gcc src/main.c
2056 ./a.out
2057 ## jesus christ what have I done
2058 gcc src/main.c
2059 ## jesus christ what have I done
2060 ./a.out
2061 gcc src/main.c
2062 ./a.out
2063 gcc src/main.c
2064 ./a.out
2065 # there, it works
2066 # I accidentally turned on airplane mode
2067 # this keyboard does NOT need that button
2068 # fuck laptops that have weird buttons
2069 gcc src/main.c
2070 ./a.out
2071 gcc src/main.c
2072 ./a.out
2073 micro ~/.bashhistory
2074 history
or my bash history, I guess
hi
check the comments for me slowly going insane