Last active
July 28, 2017 00:47
-
-
Save Xvezda/730841ab76c25e2ac77e99c8482bcc57 to your computer and use it in GitHub Desktop.
Pseudo x86 Assembly Interpreter
This file contains 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
/* | |
* Pseudo Assembly interpreter | |
* by. Xvezda (xvezda@naver.com) | |
* | |
* < The MIT License > | |
*/ | |
#include <stdio.h> | |
#include <string.h> | |
#include <stdlib.h> | |
#include <ctype.h> | |
#define MEM_SIZE 1024 // 0x400 | |
#define BUF_SIZE 256 // 0x100 | |
#define STR2(x) #x | |
#define STR(x) STR2(x) | |
#define CMP_STR(t, s) \ | |
(!memcmp((t), (s), sizeof(s) - 1)) | |
#define CMP_SUB \ | |
if (0) {} | |
#define CMP_END \ | |
else { \ | |
printf("Error: Bad register name.\n"); \ | |
status = 1; \ | |
break; \ | |
}; | |
#define CMP_REG(t, n, exp) \ | |
else if (CMP_STR((t), #n)) { \ | |
exp; \ | |
} | |
#define GEN_REG(n) \ | |
union { \ | |
int e##n##x; \ | |
short n##x; \ | |
struct { \ | |
char n##l; \ | |
char n##h; \ | |
}; \ | |
}; | |
#define TRW_ERR(e, m) \ | |
if ((e)) { \ | |
printf(m); \ | |
status = 1; \ | |
break; \ | |
} | |
#define _TRW_ERR(x, f, m) \ | |
if ((f(*x))) { \ | |
printf(m); \ | |
status = 1; \ | |
break; \ | |
} | |
#define INS_TMP(mp, dst, src, exp) \ | |
do { \ | |
int data; \ | |
_TRW_ERR(dst, isdigit, "Error: Dest cannot be a number.\n"); \ | |
if (isdigit(*src)) { \ | |
data = atoi(src); \ | |
} else { \ | |
CMP_SUB \ | |
CMP_REG(src, eax, data = mp->reg.eax) \ | |
CMP_REG(src, ebx, data = mp->reg.ebx) \ | |
CMP_REG(src, ecx, data = mp->reg.ecx) \ | |
CMP_REG(src, edx, data = mp->reg.edx) \ | |
CMP_REG(src, esp, data = mp->reg.esp) \ | |
CMP_REG(src, ebp, data = mp->reg.ebp) \ | |
CMP_END \ | |
} \ | |
CMP_SUB \ | |
CMP_REG(dst, eax, mp->reg.eax exp data) \ | |
CMP_REG(dst, ebx, mp->reg.ebx exp data) \ | |
CMP_REG(dst, ecx, mp->reg.ecx exp data) \ | |
CMP_REG(dst, edx, mp->reg.edx exp data) \ | |
CMP_REG(dst, esp, mp->reg.esp exp data) \ | |
CMP_REG(dst, ebp, mp->reg.ebp exp data) \ | |
CMP_END \ | |
} while (0); | |
#define _INS_TMP(mp, trg, exp) \ | |
TRW_ERR(isdigit(*trg), "Error: Bad register.\n"); \ | |
CMP_SUB \ | |
CMP_REG(trg, eax, mp->reg.eax = exp mp->reg.eax) \ | |
CMP_REG(trg, ebx, mp->reg.ebx = exp mp->reg.ebx) \ | |
CMP_REG(trg, ecx, mp->reg.ecx = exp mp->reg.ecx) \ | |
CMP_REG(trg, edx, mp->reg.edx = exp mp->reg.edx) \ | |
CMP_REG(trg, esp, mp->reg.esp = exp mp->reg.esp) \ | |
CMP_REG(trg, ebp, mp->reg.ebp = exp mp->reg.ebp) \ | |
CMP_END | |
typedef struct REGISTERS | |
{ | |
GEN_REG(a); | |
GEN_REG(b); | |
GEN_REG(c); | |
GEN_REG(d); | |
int esp; | |
int ebp; | |
int esi; | |
int edi; | |
} reg_t; | |
typedef struct MEMORY | |
{ | |
int block[MEM_SIZE]; | |
reg_t reg; | |
} mem_t; | |
void showm(void); | |
void showc(void); | |
void showe(const char *msg); | |
void showr(mem_t *mp); | |
void showi(void); | |
int execi(char *ins); | |
int main(int argc, char *argv[]) | |
{ | |
mem_t* mp = malloc(sizeof(mem_t)); | |
char ins[BUF_SIZE] = { 0, }; | |
showm(); | |
for (int status = 0; !status; /* NULL */) { | |
showc(); | |
scanf("%" STR(BUF_SIZE) "[^\n]s", ins); | |
switch (execi(ins)) { | |
case -1: | |
status = 1; | |
break; | |
case 1: | |
showr(mp); | |
break; | |
default: { | |
char *i = strtok(ins, ", "); | |
char *a = strtok(NULL, ", "); | |
char *b = strtok(NULL, ", "); | |
//char *c = strtok(NULL, ", "); | |
if (CMP_STR(i, "mov")) { | |
INS_TMP(mp, a, b, =); | |
break; | |
} else if (CMP_STR(i, "add")) { | |
INS_TMP(mp, a, b, +=); | |
break; | |
} else if (CMP_STR(i, "sub")) { | |
INS_TMP(mp, a, b, -=); | |
break; | |
} else if (CMP_STR(i, "xor")) { | |
INS_TMP(mp, a, b, ^=); | |
break; | |
} else if (CMP_STR(i, "or")) { | |
INS_TMP(mp, a, b, |=); | |
break; | |
} else if (CMP_STR(i, "and")) { | |
INS_TMP(mp, a, b, &=); | |
break; | |
} else if (CMP_STR(i, "inc")) { | |
_INS_TMP(mp, a, 1+); | |
break; | |
} else if (CMP_STR(i, "dec")) { | |
_INS_TMP(mp, a, -1+); | |
break; | |
} else if (CMP_STR(i, "not")) { | |
_INS_TMP(mp, a, ~); | |
break; | |
} else if (CMP_STR(i, "push")) { | |
TRW_ERR(mp->reg.esp >= MEM_SIZE, "Error: Stack overflow!\n"); | |
int data; | |
if (isdigit(*a)) { | |
data = atoi(a); | |
} else { | |
CMP_SUB | |
CMP_REG(a, eax, data = mp->reg.eax) | |
CMP_REG(a, ebx, data = mp->reg.ebx) | |
CMP_REG(a, ecx, data = mp->reg.ecx) | |
CMP_REG(a, edx, data = mp->reg.edx) | |
CMP_REG(a, esp, data = mp->reg.esp) | |
CMP_REG(a, ebp, data = mp->reg.ebp) | |
CMP_END | |
} | |
mp->block[mp->reg.esp] = data; | |
mp->reg.esp++; | |
break; | |
} else if (CMP_STR(i, "pop")) { | |
mp->reg.esp--; | |
TRW_ERR(mp->reg.esp < 0, "Error: Stack underflow!\n"); | |
int data = mp->block[mp->reg.esp]; | |
CMP_SUB | |
CMP_REG(a, eax, mp->reg.eax = data) | |
CMP_REG(a, ebx, mp->reg.ebx = data) | |
CMP_REG(a, ecx, mp->reg.ecx = data) | |
CMP_REG(a, edx, mp->reg.edx = data) | |
CMP_REG(a, esp, mp->reg.esp = data) | |
CMP_REG(a, ebp, mp->reg.ebp = data) | |
CMP_END | |
break; | |
} else if (CMP_STR(i, "leave")) { | |
mp->reg.esp = mp->reg.ebp; | |
mp->reg.esp--; | |
TRW_ERR(mp->reg.esp < 0, "Error: Stack underflow!\n"); | |
mp->reg.ebp = mp->block[mp->reg.esp]; | |
break; | |
} else if (CMP_STR(i, "nop")) { | |
__asm ("nop;"); // do nothing | |
break; | |
} else if (CMP_STR(i, "help")) { | |
showi(); | |
break; | |
} | |
showe(ins); | |
} break; | |
} | |
getchar(); // clear stdin | |
} | |
printf("[Exit code - %d]\n", mp->reg.eax); | |
free(mp); | |
return EXIT_SUCCESS; | |
} | |
void showm(void) | |
{ | |
printf("PSEUDO ASSEMBLY INTERPRETER v1.0b\n" | |
"by. Xvezda\n\n" | |
"Type \"exit\" to quit, \"help\" for more informations\n"); | |
} | |
void showc(void) | |
{ | |
printf(">>>\x20"); | |
} | |
void showe(const char *msg) | |
{ | |
printf("Error: There is no such instruction like \"%s\"\n", msg); | |
} | |
void showr(mem_t *mp) | |
{ | |
printf("[REGISTERS]\n" | |
"EAX: %d\n" | |
"EBX: %d\n" | |
"ECX: %d\n" | |
"EDX: %d\n" | |
"ESI: %d\n" | |
"EDI: %d\n" | |
"ESP: %d\n" | |
"EBP: %d\n", | |
mp->reg.eax, | |
mp->reg.ebx, | |
mp->reg.ecx, | |
mp->reg.edx, | |
mp->reg.esi, | |
mp->reg.edi, | |
mp->reg.esp, | |
mp->reg.ebp); | |
} | |
void showi(void) | |
{ | |
printf("[HELP]\n" | |
"show - show list of registers.\n" | |
"exit - quit program.\n" | |
"[SUPPORT]\n" | |
"mov, add, sub, xor, or, and, inc, dec, not, push, pop\n"); | |
} | |
int execi(char *ins) | |
{ | |
if (CMP_STR(ins, "exit") || CMP_STR(ins, "quit")) { | |
return -1; | |
} else if (CMP_STR(ins, "show") | |
|| CMP_STR(ins, "info") | |
|| CMP_STR(ins, "view")) { | |
return 1; | |
} | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment